我在这里读过,如果编译器memset
知道传递的内存缓冲区不再使用,它可以自由地删除调用。这怎么可能?在我看来(从核心语言的角度来看)memset
只是一个常规函数,编译器无权假设它内部发生的任何事情都没有副作用。
在链接的文章中,他们展示了 Visual C++ 10 如何删除memset
. 我知道 Microsoft 编译器在标准合规性方面并不领先,所以我问 - 是根据标准,还是只是 msvc-ism?如果符合标准,请详细说明;)
编辑: @Cubbi
以下代码:
void testIt(){
char foo[1234];
for (int i=0; i<1233; i++){
foo[i] = rand()%('Z'-'A'+1)+'A';
}
foo[1233]=0;
printf(foo);
memset(foo, 0, 1234);
}
在 mingw 下编译,行:
g++ -c -O2 -frtti -fexceptions -mthreads -Wall -DUNICODE -o main.o main.cpp
g++ -Wl,-s -Wl,-subsystem,console -mthreads -o main.exe main.o
objdump -d -M intel -S main.exe > dump.asm
给出输出:
4013b0: 55 push ebp
4013b1: 89 e5 mov ebp,esp
4013b3: 57 push edi
4013b4: 56 push esi
4013b5: 53 push ebx
4013b6: 81 ec fc 04 00 00 sub esp,0x4fc
4013bc: 31 db xor ebx,ebx
4013be: 8d b5 16 fb ff ff lea esi,[ebp-0x4ea]
4013c4: bf 1a 00 00 00 mov edi,0x1a
4013c9: 8d 76 00 lea esi,[esi+0x0]
4013cc: e8 6f 02 00 00 call 0x401640
4013d1: 99 cdq
4013d2: f7 ff idiv edi
4013d4: 83 c2 41 add edx,0x41
4013d7: 88 14 1e mov BYTE PTR [esi+ebx*1],dl
4013da: 43 inc ebx
4013db: 81 fb d1 04 00 00 cmp ebx,0x4d1
4013e1: 75 e9 jne 0x4013cc
4013e3: c6 45 e7 00 mov BYTE PTR [ebp-0x19],0x0
4013e7: 89 34 24 mov DWORD PTR [esp],esi
4013ea: e8 59 02 00 00 call 0x401648
4013ef: 81 c4 fc 04 00 00 add esp,0x4fc
4013f5: 5b pop ebx
4013f6: 5e pop esi
4013f7: 5f pop edi
4013f8: c9 leave
4013f9: c3 ret
在 4013ea 行有 memset 调用,所以 mingw 没有删除它。由于 mingw 在 Windows 皮肤中确实是 GCC,我想 GCC 也是这样做的——我会在重新启动到 linux 时检查它。
仍然无法找到这样的编译器?
编辑2:
我刚刚发现了 GCC 的__attribute__ ((pure))
. 所以并不是编译器知道 memset 的一些特殊之处并忽略它,只是它的标题中允许使用它 - 使用它的程序员也应该看到它;)我的 mingw 在memset
声明中没有这个属性,因此它没有从无论如何组装 - 正如我所期望的那样。我将不得不对此进行调查。