【发布时间】:2014-05-27 12:06:39
【问题描述】:
最近我讨论过有人想像if (A + B < 2 * max(A, B)) 这样检查有符号整数溢出。让我们暂时忽略逻辑本身是错误的,并讨论 C/C++ 上下文中的有符号整数溢出。 (我相信它完全从 C 继承了这部分标准)。
当前的 GCC 会优化哪些需要有符号整数溢出的检查,哪些不会?
由于原文的表述不是那么好,而且显然存在争议,我决定稍微改变一下问题,但将原文留在下面。
下面使用的所有示例都经过测试 gcc 版本 4.7.2 (Debian 4.7.2-5) 并使用 -O3 编译
也就是说,它是未定义的,而 GCC 臭名昭著地使用它来执行一些分支简化。想到的第一个例子是
int i = 1;
while (i > 0){
i *= 2;
}
产生一个无限循环。这种优化启动的另一种情况是
if (A + 2 < A){
/* Handle potential overflow */
}
如果A 是有符号整数类型,则溢出分支将被完全删除。
更有趣的是,一些容易可证明整数溢出的情况并没有受到影响,例如
if (INT_MAX + 1 < 0){
/* You wouldn't write this explicitly, but after static analysis the program
could be shown to contain something like this. */
}
这会触发您期望使用二进制补码表示的分支。同样,此代码保持条件分支不变
int C = abs(A);
if (A + C < 0){
/* For this to be hit, overflow or underflow had to happen. */
}
现在的问题是,是否有一个大致类似于if (A + B < C) 或if (A + B < c) 的模式会被优化掉?当我在写这篇文章之前四处搜索时,似乎最后一个 sn-p 应该被优化掉,但我无法在没有明确使用常量的溢出检查中重现这种错误。
【问题讨论】:
-
您的最后一个示例比其他示例复杂得多。它需要通过函数调用跟踪 A 和 C 之间的依赖关系,并在其他函数已经需要的基础上对该函数进行“数学理解”。
-
我真的不明白你到底要什么。 “看起来大致像这样”有点模糊
-
问题是,因为它是未定义的行为,任何答案都是有效的。
-
@KerrekSB 我会说它臭名昭著,因为试图检查溢出以防止所述恶意用户搞砸事情,以使代码运行更快的名义得到优化。老实说,我认为标准的整个部分都是一团糟(可以通过将其定义为实现而不是未定义来防止)。
-
@Xarn 我只能说你错了。事实上,在无符号类型的情况下定义行为存在很多反对意见。定义的行为在某些架构上具有显着的运行时成本。并且某些架构确实(或至少确实)捕获了溢出,这也是造成这种未定义行为的重要原因。
标签: c++ c gcc compiler-optimization integer-overflow