为什么 C++如果写入后没有代码,编译器只会消除无用的写入?

发布于 2024-12-02 05:58:58 字数 1089 浏览 1 评论 0原文

我正在检查 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;
}

从机器代码中消除了在 return 之前对 memset() 的调用(我检查了反汇编)。这是完全合理的 - 如果之后没有从 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() 调用会有用?

I'm inspecting Visual C++ 10 optimization capabilities and found a rather curious thing. All code herein is compiled with /O2.

In the following code:

int _tmain(int argc, _TCHAR* argv[])
{
    char buffer[1024] = {};
    MessageBoxA( 0, buffer, buffer, 0 );
    memset( buffer, 0, sizeof( buffer ) );
    return 0;
}

the call to memset() before return is eliminated from the machine code (I inspect the disassembly). This is perfectly reasonable - if there're no reads from buffer afterwards then memset() is useless and if the developers really want to overwrite the buffer thay can use SecureZeroMemory() instead.

However in the following code:

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;
}

the call to memset() is not eliminated. That call has no influence on observed behavior and could be eliminated just as well as in the first snippet.

This can be a compiler deficiency or it can be useful somehow - I can't decide.

Why could leaving memset() call in the machine code emitted for the second snippet be useful?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你是暖光i 2024-12-09 05:58:58

编译器可能无法判断 MessageBoxA 没有创建 buffer 的别名,稍后供 Sleep 使用。因此它无法通过“假设”检查。

The compiler probably can't tell that MessageBoxA doesn't create an alias to buffer that's then used by Sleep later. Thus it fails the "as-if" check.

请恋爱 2024-12-09 05:58:58

编译器可以查看memset的内容并确定它的作用。 Sleep() 是一个与内核交互的系统调用,其行为取决于代码运行的 Windows 版本;包括尚未实施的 Windows 版本的可能性。编译器根本无法知道该函数将做什么,因此它无法围绕它进行优化。

MessageBox 也是如此,这让我惊讶于 memset 在第一个版本中被删除了。

可以肯定的是,对 memset 的调用在任何当前或未来版本的 Windows 上都不会出现问题,但这不是我希望编译器尝试猜测的事情。

The compiler can look at the contents of memset and determine what it does. Sleep() is a system call that interacts with the kernel and its behavior is dependent on what version of Windows the code is run on; including the possibility of yet to implemented versions of Windows. There is simply no way for the compiler to know what the function will do and therefore there is no way for it optimize around it.

The same can be said of MessageBox which makes me surprised that memset got removed in the first version.

It is a safe bet that the call to memset will not be a problem on any current or future version of Windows, but that's not something I want the compiler to try to guess about.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文