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,它必须小于另一个整数.如果它更大,则循环终止.
任何人都可以向我解释这种行为吗?
编译器正在进行优化以转换a + 1 < b为a < b - 1.但是,如果b是,INT_MIN那么这将是下溢,这是行为的变化.这是它的警告.
当然,您可能会说这是不可能的,但编译器的资源有限,无法对数据路径进行深入分析.
添加b >= 0可以解决问题的检查.
编辑:另一种可能性是它正在移动a >= 0到循环外部,因为(假设没有溢出)它永远不会改变.同样,该假设可能对所有输入都无效(即,如果b为负).您需要检查最终装配以查看它实际执行的操作.
C++ 标准规定,如果有符号整数计算产生的结果超出该类型的可表示范围,则行为未定义。整数溢出为UB。一旦 UB 发生,实施就可以自由地做任何它想做的事。
许多编译器在明确假设 UB 不会发生的情况下应用优化。[或者如果确实如此,代码可能是错误的,但这是你的问题!]
此编译器通知您,它正在将此类优化应用于计算,但无法通过分析代码确定 UB 不会发生。
您的选择一般是:
我会推荐最后一个选项。a对和进行简单的范围测试b就足够了。
我的猜测是,编译器发出此错误是因为循环处理完全未知的值,并且它无法足够好地分析数据流来确定 UB 是否会发生。
我们凭借超强的推理能力可以说服自己UB不会发生,因此我们可以忽略这个错误。事实上,仔细阅读错误消息可能会让我们怀疑它是否相关。这两个常数值C1和在哪里C2?
我们可能还注意到a永远不会变成负数,那么为什么该测试要在循环中进行呢?我可能会重写代码来抑制错误(但根据经验,这可能是一个弄巧成拙的练习)。尝试一下,看看会发生什么(并避免不必要的括号混乱):
if (a >= 0) {
while (a < b) {
...
++a;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
864 次 |
| 最近记录: |