我正在检查 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()
调用会有用?
编译器可能无法判断
MessageBoxA
没有创建 buffer
的别名,然后由 Sleep
使用。因此它未通过“假设”检查。
编译器可以查看
memset
的内容并确定它的作用。 Sleep()
是一个与内核交互的系统调用,其行为取决于代码运行的Windows版本;包括尚未实施的 Windows 版本的可能性。 编译器根本无法知道该函数将做什么,因此无法对其进行优化。
同样的情况也适用于
MessageBox
,这让我惊讶于memset
在第一个版本中被删除了。
可以肯定的是,对
memset
的调用在任何当前或未来版本的 Windows 上都不会出现问题,但这不是我希望编译器尝试猜测的事情。