c++ - 为什么 C++11 及更高版本的现代编译器对此进行了优化

标签 c++

<分区>

我迷路了..我想玩一下compiler explorer尝试多线程 C 代码,并从一段简单的代码开始。代码用-O3编译。

static int hang = 0;

void set_hang(int x) {
    hang = x;
}

void wait() {
    while (hang != 0) {
        // wait...
    }
}

令我惊讶的是,这是编译器输出:

set_hang(int):
        mov     dword ptr [rip + hang], edi
        ret
wait():
        ret

我花了一段时间才注意到我正在将代码编译为 C++ 而不是 C。切换到 C 给了我一些我期望的东西:

set_hang:
        mov     DWORD PTR hang[rip], edi
        ret
wait:
        mov     eax, DWORD PTR hang[rip]
        test    eax, eax
        je      .L3
.L5:
        jmp     .L5
.L3:
        ret

因此,当编译为 C++ 时,wait() 总是返回,无论之前将哪个值传递给 set_hang()。我通过在我的 PC 上编译和代码确认了这一点。这段代码立即存在,而我希望它永远挂起:

int main(void) {
    set_hang(1);
    wait();
    return 0;
}   

事实上,如果我用 gcc 而不是 g++ 编译它,它就会挂起。

我尝试了不同的编译器(Clang 和 GCC),这只发生在 Clang 12.0.0 或更高版本或 GCC 10.1 或更高版本上。如果我通过 --std=c++98 也会发出我期望的代码,所以它似乎是特定于 C++11 及更高版本的代码。

hang 中删除 static 关键字不会影响发出的程序集。

这里发生了什么?我写 C++ 已经几个月了,所以我可能缺少一些关于最新和最伟大的奇异 C++ 黑魔法的知识,但这是非常简单的代码。我一无所知。


编辑:甚至这个程序也被完全优化掉了:

// test.cpp
static int hang = 0;

static void set_hang(int x) {
    hang = x;
}

static void wait() {
    while (hang != 0) {
        // wait...
    }
}

int main(void) {
    set_hang(1);
    wait();
    return 0;
}

编译器输出:

main:
        xor     eax, eax
        ret

对于 Ubuntu 上的 GCC 版本 10.3.0:

此命令将挂起:g++ -O1 -o test test.cpp && ./test

而这个命令不会:g++ -O2 -o test test.cpp && ./test

最佳答案

这是因为以下规则:

[intro.progress]

The implementation may assume that any thread will eventually do one of the following:

  • terminate,
  • make a call to a library I/O function,
  • perform an access through a volatile glvalue, or
  • perform a synchronization operation or an atomic operation.

编译器能够证明进入循环的程序永远不会做任何列出的事情,因此允许假设永远不会进入循环。

关于c++ - 为什么 C++11 及更高版本的现代编译器对此进行了优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70506857/

相关文章:

c++ - 如何在 g++ 中选择处理器(MIPS R2000)?

c++ - 避免在 Qt 中使用非符号常量

c++ - 修改unique_ptrs的priority_queue

c++ - OpenMP:获取正在运行的线程总数

c++ - DELAYLOAD 在 Qt LNK2001 : unresolved external symbol 中给出链接错误

c++ - 为什么我的凸包周长计算不起作用?

c++ - 用于查找哪些函数最终会导致调用低级函数(列表)的工具

c++ - 如何在 Bazel 项目中设置 Catch2

c++ - 基于字符串的用户定义文字可以是强类型的吗?

c++ - 如果我这样写我的单例类会导致什么错误