繁体   English   中英

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

[英]C++ while loop optimization not working properly

我有这段代码:

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

我用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的检查可以解决问题。

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

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

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

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

您的选择一般是:

  1. 让自己满意UB不会发生,并忽略警告。
  2. 允许UB发生并承担后果。
  3. 重写代码,以便UB真的不会发生,编译器知道它不会发生,并且警告应该消失。

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


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

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

我们可能还会注意到a永远不会消极,所以为什么循环中的测试呢? 我可能会重写代码以抑制错误,(但从经验来看,这可能是一个弄巧成拙的练习)。 试试这个,看看会发生什么(并避免不必要的括号杂乱):

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

编译器警告你的是它假设在原始代码中没有发生签名溢出

警告并不意味着“我即将编写一个可能引入溢出的优化。”

换句话说,如果您的程序依赖于溢出(即不是高度可移植),那么编译器正在进行的优化可能会改变其行为。 (因此,请自行验证此代码不依赖于溢出)。

例如,如果你有“a + b> c”,并且你依赖于这个测试在+ b算术环绕时失败(典型的二进制补码行为),那么如果这恰好被代数转换为“a> c - b“,那么它可能会成功,因为c - b可能不会溢出,并产生小于a的值。

注意:只有C程序可以调用未定义的行为。 当编译器不正确时,它们是“不合格的”。 如果编译器符合(C标准)符合代码的错误,编译器只能是不符合(对C标准)。 改变正确的可移植行为的优化是不合格的优化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM