C++ while循环优化不能正常工作

del*_*ler 5 c c++ gcc integer-overflow compiler-optimization

我有这段代码:

#include <stdio.h>

int main(int argc, const char** argv)
{
    int a = argv[0][0];
    int b = argv[0][1];

    while ((a >= 0) &&
           (a < b))
    {
        printf("a = %d\n", a);
        a++;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我正在编译它gcc-4.5 -02 -Wstrict-overflow=5.

编译器对我大吼大叫 warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2

这究竟是什么意思?

如果我是正确的,这个循环永远不会导致溢出,因为要增加a,它必须小于另一个整数.如果它更大,则循环终止.

任何人都可以向我解释这种行为吗?

Sto*_*ica 7

编译器正在进行优化以转换a + 1 < ba < b - 1.但是,如果b是,INT_MIN那么这将是下溢,这是行为的变化.这是它的警告.

当然,您可能会说这是不可能的,但编译器的资源有限,无法对数据路径进行深入分析.

添加b >= 0可以解决问题的检查.

编辑:另一种可能性是它正在移动a >= 0到循环外部,因为(假设没有溢出)它永远不会改变.同样,该假设可能对所有输入都无效(即,如果b为负).您需要检查最终装配以查看它实际执行的操作.


dav*_*pfx 2

C++ 标准规定,如果有符号整数计算产生的结果超出该类型的可表示范围,则行为未定义。整数溢出为UB。一旦 UB 发生,实施就可以自由地做任何它想做的事。

许多编译器在明确假设 UB 不会发生的情况下应用优化。[或者如果确实如此,代码可能是错误的,但这是你的问题!]

此编译器通知您,它正在将此类优化应用于计算,但无法通过分析代码确定 UB 不会发生。

您的选择一般是:

  1. 让自己确信 UB 不会发生,并忽略警告。
  2. 允许 UB 发生并承担其后果。
  3. 重写代码,使 UB 确实不会发生,并且编译器知道它不会发生,并且警告应该消失。

我会推荐最后一个选项。a对和进行简单的范围测试b就足够了。


我的猜测是,编译器发出此错误是因为循环处理完全未知的值,并且它无法足够好地分析数据流来确定 UB 是否会发生。

我们凭借超强的推理能力可以说服自己UB不会发生,因此我们可以忽略这个错误。事实上,仔细阅读错误消息可能会让我们怀疑它是否相关。这两个常数值C1和在哪里C2

我们可能还注意到a永远不会变成负数,那么为什么该测试要在循环中进行呢?我可能会重写代码来抑制错误(但根据经验,这可能是一个弄巧成拙的练习)。尝试一下,看看会发生什么(并避免不必要的括号混乱):

if (a >= 0) {
  while (a < b) {
    ...
    ++a;
  }
}
Run Code Online (Sandbox Code Playgroud)