优化的 clang 处理溢出

Optimized clang handling overflow

我有一些我的优化器没有预料到的奇怪行为。基本上这是一个变量溢出的情况,我试图用来处理它的逻辑正在中断。

这是完整的程序 (weird.cpp):

#include <stdio.h>

class Example {
public:
  void Change() {
    change_count_++;

    // Check for overflow. If it does, set to 1 which is still valid
    if(change_count_ <= 0) {
      change_count_ = 1;
    }
  }

public:
  int change_count_ = 0;
};

int main() {
  Example example;
  printf("Pre: %d\n", example.change_count_);

  example.change_count_ = 2147483647; // MAX_INT
  printf("Mid: %d\n", example.change_count_);

  example.Change();
  printf("Pst: %d\n", example.change_count_);

  return 0;
}

使用这些命令构建时:

gcc  -fPIC -g3 -O1 -g   -std=gnu++11  weird.cpp -o optimized
gcc weird.cpp -o normal

程序 normal 按预期执行,输出如下:

Pre: 0
Mid: 2147483647
Pst: 1

但是 optimized 给出了以下意想不到的行为:

Pre: 0
Mid: 2147483647
Pst: -2147483648

附加到调试器显示增量是在函数的最后完成的。 C++ 中是否未定义溢出行为?或者我应该用不同的方式处理这个问题吗?

这是我使用的 clang 版本:

tiny.local:~/scratch/weird_inc$ gcc -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

我在 Ubuntu 中用 gcc 5.4.0 进行了测试,它给了我正确的答案。

有符号整数溢出 is undefined behavior in the current C++ standard

编译器可以自由假设未定义的行为永远不会发生,并且不需要编译依赖于未定义行为的代码。

这意味着编译器可以安全地假设递增大于 0 的正值永远不会产生负值或 0。

您的编译器正在积极优化代码。编译器看到变量被初始化为正值,并递增。因此,编译器假定结果不能为负或 0,因此比较甚至不会被编译,因为它永远不可能为真。