注: 这里只是分析这三种方式的底层实现原理, 它们在应用场景上是有区别的
分析环境:
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);