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

C++ while loop optimization not working properly

本文关键字:工作 常工作 while 循环 优化 不能 c++      更新时间:2023-10-16

我有这样的代码段:

#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 = %dn", a);
        a++;
    }
    return 0;
}

,我正在编译它与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递增,它必须小于另一个整数。

谁能给我解释一下这种行为?

编译器正在优化将a + 1 < b转换为a < b - 1。然而,如果bINT_MIN,那么这将下溢,这是行为的变化。这就是它的警告。

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

增加b >= 0可能解决问题的检查

Edit :另一种可能性是它将a >= 0移到循环之外,因为(假设没有溢出)它永远不会改变。同样,该假设可能对所有输入都无效(例如,如果b为负)。您需要检查最终的程序集,看看它实际做了什么。

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

许多编译器在显式假设不发生UB的情况下应用优化。或者,如果它是,代码可能是错误的,但这是你的问题!)

这个编译器通知你,它正在应用这样的优化计算,它无法从分析代码中确定UB不发生。

你的选择通常是:

  1. 确信不可能发生UB,忽略警告。
  2. 允许UB发生并承担后果。
  3. 重写代码,这样UB真的不会发生,编译器知道它不会发生,警告应该消失。

我推荐最后一个选项。ab的简单范围测试应该足够好了。


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

我们凭借优越的推理能力可以说服自己UB不可能发生,所以我们可以忽略这个错误。事实上,仔细阅读错误消息可能会让我们问它是否相关。C1C2这两个常量在哪里?

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

if (a >= 0) {
  while (a < b) {
    ...
    ++a;
  }
}

编译器警告您的是,它假设在原始代码中没有发生有符号溢出

警告并不意味着"我即将编写的优化可能会导致引入溢出。"

换句话说,如果你的程序依赖于溢出(即不是高度可移植的),那么编译器正在做的优化可能会改变它的行为。(所以请自己验证这段代码不依赖于溢出)。

例如,如果您有"a + b> c",并且您依赖于该测试在a + b算术包装时失败(典型的两个的互补行为),那么如果它碰巧在代数上转换为"a> c - b",那么它可能成功,因为c - b可能碰巧没有溢出,并产生小于a的值。

注意:只有C程序可以调用未定义行为。当编译器不正确时,它们是"不一致的"。如果编译器对符合(C标准)的代码做了错误的事情,那么它只能是不符合(C标准)的。一个改变了正确的,可移植的行为的优化是一个不符合的优化。