我正在检查Visual C ++ 10优化功能,并发现了一个相当奇怪的事情。此处的所有代码均使用/ O2编译。
在以下代码中:
int _tmain(int argc, _TCHAR* argv[])
{
char buffer[1024] = {};
MessageBoxA( 0, buffer, buffer, 0 );
memset( buffer, 0, sizeof( buffer ) );
return 0;
}
从机器代码中删除memset()
之前return
的调用(我检查反汇编)。这是完全合理的 - 如果之后没有来自buffer
的读取,那么memset()
是无用的,如果开发人员真的想要覆盖缓冲区,那么可以使用SecureZeroMemory()
代替。
但是在以下代码中:
int _tmain(int argc, _TCHAR* argv[])
{
char buffer[1024] = {};
MessageBoxA( 0, buffer, buffer, 0 );
memset( buffer, 0, sizeof( buffer ) );
Sleep( 0 ); //<<<<<<<<<<<<<<<<<<<<<<<<<<< Extra code
return 0;
}
对memset()
的调用未被删除。该调用对观察到的行为没有影响,可以像在第一个片段中一样被消除。
这可能是一个编译器缺陷,或者它可能在某种程度上有用 - 我无法决定。
为什么在为第二个代码段发出的机器代码中调用memset()
会有用吗?
答案 0 :(得分:18)
编译器可能无法判断MessageBoxA
是否未创建buffer
的别名,后来由Sleep
使用。因此它没有通过“假设”检查。
答案 1 :(得分:2)
编译器可以查看memset
的内容并确定它的作用。 Sleep()
是一个与内核交互的系统调用,其行为取决于运行代码的Windows版本;包括尚未实现的Windows版本的可能性。编译器根本无法知道函数将执行什么操作,因此无法围绕它进行优化。
同样可以说MessageBox
让我感到惊讶的是memset
在第一个版本中被删除了。
可以肯定的是,对memset
的调用在任何当前或未来版本的Windows上都不会出现问题,但这不是我希望编译器试图猜测的。