VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 1575|回复: 5

[原创] 内存操作函数memset,memcpy的故事。

[复制链接]
001
75_avatar_middle
在线会员 发表于 2019-4-11 11:21:59 | 显示全部楼层 |阅读模式
这一回,说说内存操作memset,memcpy函数,
说起这两个函数,是大家常用的两个函数,很简单,如果已懂,就不要看了。是老生常谈。跳过。
这些是给那些说懂又不懂,说不懂又懂的看的。
从例子开始。
下面假设是颜色数据,r红,g绿,b蓝,a透明值。
  1. char src_abgr[16] = {
  2. 0x0f,0x0e,0x0d,0x0c,
  3. 0x0b,0x0a,0x09,0x08,
  4. 0x07,0x06,0x05,0x04,
  5. 0x03,0x02,0x01,0x0
  6. };
复制代码
  1. char dst_abgr[16];
复制代码

任务一:初始dst_rgba为黑色。
  1. memset(dst_rgba,0x0,16);
复制代码

任务二:初始st_rgba为红色
  1. memset(dst_rgba,0xff0000ff,16);
复制代码

这是不对地。为什么不对,后面调试会给出。
这样做
  1. DWORD dwRed = 0xff0000ff;
  2. for (int i = 0;i<16;i += 4) memcpy(&dst_abgr[i], &dwRed,4);
复制代码

认为不错,但这不是唯一的方法,反汇编过来,明显有点繁琐。
因为它是反复调用C库函数_memcpy,可以简化成这样
  1. DWORD dwYellow = 0xff00ffff;//改颜色是为了调试好辨别。
  2. int len = 16/4;
  3. _asm{
  4.        cld
  5.        lea edi,dst_abgr
  6.        mov ecx,len
  7.        mov eax, dwYellow
  8.        rep stos
  9. }
复制代码

主要是让它不要在汇编里又反复调用_memcpy。
任务三:将源拷贝到目的
  1. memcpy(dst_abgr, src_abgr, 16);
复制代码

这本是最简化的代码,但依然可以优化
  1. _asm {
  2.         movdqu xmm0,src_abgr
  3.         movdqu dst_abgr,xmm0
  4. }
复制代码

movdqu是sse2的128位整数传送指令,一次传输16字节,实际上上述只传送一次,要多次这样
  1. int len = 16/16;
  2. _asm {
  3.         lea esi, src_abgr
  4.         lea edi, dst_abgr
  5.         mov ecx, len
  6.         cont:
  7.         movdqu xmm0, [esi]
  8.         movdqu[edi], xmm0
  9.         add esi, 16
  10.         add edi, 16
  11.         loop cont
  12. }
复制代码

当然还可以用mmx64位传送,不过要多传1次。代码上没写。忽略
  1. int len = 16/8;
  2. _asm {
  3.         lea esi, src_abgr
  4.         lea edi, dst_abgr
  5.         mov ecx, len
  6.         cont:
  7.         movq mm0, [esi]
  8.         movq[edi], mm0
  9.         add esi, 8
  10.         add edi, 8
  11.         loop cont
  12. }
复制代码

它们与memcpy的区别,它在传送中可以再计算。而memcpy做不到。
附带的话学习mmx,sse指令要记住那些指令是整数指令,哪些是单精度,哪些是双精度指令,
哪些指令可以混用,哪些不能混用。
至此,发现问题了吧,memcpy是一个未知好坏的函数。别人在用memcpy。
那里,是可以有所作为的地方。为什么这样,因为编译器不知道你要怎么传,系统支不支持
MMX,SSE指令,只能字节传。正因为这样,才产生出很多故事。

下面进入调试
1)确定断点,鼠标单击程序编辑窗口行的左边,显红点,即为断点。点选程序首行,
   然后点击本地Windows调试器或F5
2) 在菜单调试->窗口选内存,再选内存1。
   在菜单调试->窗口选寄存器.
   窗口布局如下
内存操作函数memset,memcpy的故事。
要设置断点,不然调试不停,就什么都看不到。
内存操作函数memset,memcpy的故事。
鼠标移到src_abgr地址变量,会出现浮动提示,鼠标再移到这个浮动提示里,右键弹出菜单
   选择复制值。然后再内存1地址出粘贴,去掉多余的框框..然后回车。src_abgr的内容会显示出来。
内存操作函数memset,memcpy的故事。 )
鼠标移到dst_abgr地址变量,复制值,再粘到内存地址1,去掉数值后多余的回车。
   就从dst_abgr地址显示出内容。改内存地址上没初始,系统置cccccccc...
以下按F10逐过程执行。
内存操作函数memset,memcpy的故事。
单步执行后目的数据在内存地址上的存放情况。
内存操作函数memset,memcpy的故事。
这里查看反汇编是为了了解
  1. for(int i=0;i<16;i+=4) memcpy(&dst_abgr[i],&dwRed,4);
复制代码
代码
循环内主要是压参数入堆栈,调用_memcpy。压参数的顺序从右到左。分别是4,dwRed,dst_abgr[ i ]。
另外看内存都为ff ff ff ff ff,这和预期是不一样地。  
说明memset是按字节置值。
  不管你设的什么,它只取1个字节,它用最低字节置值,即ff。
  很多初学者想当然认为,设什么值,它就会传什么值。实际上它只用1个字节。
内存操作函数memset,memcpy的故事。
看到内存的值,是FF0000FF 和红色是对应地。

内存操作函数memset,memcpy的故事。
停在这里,主要观察通用寄存器地址EAX,EDI,ECX这些用到的寄存器值是否赋值正确。

内存操作函数memset,memcpy的故事。
这是传送到目的内存情况,dst_abgr被置ffff00ff.黄色。内存中放置是低字节在前。
内存操作函数memset,memcpy的故事。
把鼠标箭头移到寄存器窗口内,右键菜单,然后准备勾选SSE的情况。使其显示mm64位或xmm128位寄存器。
内存操作函数memset,memcpy的故事。
传送数据到128位寄存器前,xmm0寄存器里的值的情况.目的地址上数据为memcpy的数据。
内存操作函数memset,memcpy的故事。
传送数据到128位寄存器情况。xmm0的内容为源src_abgr数据
内存操作函数memset,memcpy的故事。
目的数据被初始为0,是为下一次传送好对比数据。xmm0寄存器一直保持上次操作数据。
内存操作函数memset,memcpy的故事。
源数据通过128位寄存器xmm0传送到目的数据的情况。目的数据和寄存器是一致地。
内存操作函数memset,memcpy的故事。
这内联汇编的反汇编代码。除了地址,几乎是全码照搬。

以上只能在调试上看,如果执行,那什么也看到,程序就返回了。
到这里,明白了memset,memcpy吧。
如果不明白也不要紧,故事讲完,调试该会了吧。
会了,没事时,就继续调试。它永远做不完。
内存操作函数memset,memcpy的故事。















评分

参与人数 3威望 +2 驿站币 +6 热心值 +4 收起 理由
61_avatar_small 轩墨 + 2 + 2 很给力!
51_avatar_small Syc + 2 + 2 赞一个!
58_avatar_small 敏敏 + 2 + 2 支持原创!

查看全部评分





上一篇:五子棋纯C源码
下一篇:Debug下正常,而Release失败的真正原因
51_avatar_middle
online_admins 发表于 2019-4-11 17:37:16 | 显示全部楼层
说的很详细,支持原创!
16_avatar_middle
在线会员 发表于 2019-4-12 13:31:54 | 显示全部楼层
值得细细研究!
58_avatar_middle
online_vip 发表于 2019-4-18 18:17:25 | 显示全部楼层
好好学习,天天向上!
35_avatar_middle
在线会员 发表于 2019-4-23 15:33:24 | 显示全部楼层
感谢分享,学习了!!!!
22_avatar_middle
在线会员 发表于 2019-5-22 16:09:16 | 显示全部楼层
多谢大佬分享,经验值之谈~~~
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2019-8-19 14:59

Powered by Discuz! X3.4

© 2009-2019 cctry.com

快速回复 返回顶部 返回列表