注: 这里只是分析这三种方式的底层实现原理, 它们在应用场景上是有区别的
分析环境:
Windows SDK版本: 10.0.18362.0
编译器版本: MSVC 14.24.28314
注: 以下结果依赖于编译器和环境, 不同的环境可能实现方式不同
1. ={0}
测试代码
int a[20] = {0};
int b[3] = {0};
反汇编
// int a[20] = {0};
push 50h ;参数3是sizeof(a)
push 0 ;参数2是0
lea eax,[ebp-58h] ;参数1是数组地址
push eax
call _memset (0C410FAh) ;调用memset
add esp,0Ch ;清栈
// int b[3] = {0};
xor eax,eax ;eax清零
mov dword ptr [ebp-6Ch],eax
mov dword ptr [ebp-68h],eax
mov dword ptr [ebp-64h],eax
猜测: 对栈使用的比较多则使用memset, 比较小则直接挨个赋值0 (相当于b[0] = 0;)
目前测试得出, 小于等于40byte则直接赋值, 大于则使用memset, 相当于int a[10]或char a[40], 但这个结果可能极度依赖编译器
注: memset是 cdecl 调用约定
2. ZeroMemory
ZeroMemory是一个宏定义, 在minwinbase.h中, 定义如下
#define ZeroMemory RtlZeroMemory
RtlZeroMemory依旧是一个宏定义, 在winnt.h中, 定义如下
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
所以这个东西最终就是使用了memset
3. memset
memset笑到了最后2333, 以下是定义
void* __cdecl memset(void* _Dst, int _Val, size_t _Size);
本文探讨了在Windows环境下,数组初始化的三种方法:直接赋值、ZeroMemory宏及memset函数的底层实现原理。实验结果显示,对于小于40字节的数组,编译器倾向于直接赋值;而大于此大小的数组,则更可能调用memset进行填充。ZeroMemory最终也通过宏展开为memset调用。
1128

被折叠的 条评论
为什么被折叠?



