C语言 有符号整数周围溢出的未定义行为?



我需要帮助理解一些关于有符号整数的溢出。我在这篇文章中读过,围绕C中有符号和无符号变量的解释?C语言(或至少一些C编译器)有一种叫做"未定义行为"的东西;有符号整数溢出的结果。在这篇文章中,有人说"GCC编译器假设有符号整数不会溢出,这样编译器就可以优化";另一些人说:"在使用有符号整数的时候,你不能依赖环绕"。

我使用过Dev cpp,但我不确定这个IDE是否与GCC一起工作,所以我安装了代码块,现在我确信它与GCC一起工作(至少在我的配置中),我溢出了一个有符号的整数变量来实验人们说的事情,但我发现当它溢出时,IDE不显示错误或警告,有符号的整数显示环绕行为。所以,你能帮我澄清一下这个情况吗?

我还想问你关于"严格溢出"这个概念的帮助。而"选项"-Wstrict-overflow.

…有符号整数显示绕行行为…

下面是GCC和Clang不显示环绕行为的例子:

#include <limits.h>
#include <stdio.h>
void foo(int x)
{
if (x - INT_MAX <= 0)
printf("True.n");
else
printf("False.n");
}

如果x - INT_MAX缠绕,并且对x调用- 2,则x - INT_MAX将缠绕到INT_MAX。(例如,如果INT_MAX是231−1,则−2−(231−1)=−231−1,然后对232进行模化,得到−231−1 + 232= 231−1。)那么x - INT_MAX将为正,因此x - INT_MAX <= 0将为假。)因此,例程可以输出"False"。有时它被称为。

然而,当我们用GCC和-O3编译它时,我们看到编译器已经优化为只输出"True"的代码。这表明编译器没有假设算术包装。

编译器或其编写者可以推断:

  • 如果x - INT_MAX没有溢出,那么它必须给出小于或等于零的结果,因为x没有大于INT_MAXint值。在这种情况下,我们必须执行printf("True.n");
  • 如果x - INT_MAX溢出,则该行为未被C标准定义。在这种情况下,我们可以执行任何我们想要的代码,并且更容易优化执行与另一种情况相同的代码,printf("True.n");

这相当于推理:

  • x - INT_MAX不溢出。因此,它小于或等于零,所以x - INT_MAX <= 0总是为真,printf("True.n");总是被执行。所以我们可以抛弃else的情况。

GCC和Clang有一个开关-fwrapv,它通过定义有符号整数的加法、减法和乘法来扩展C标准。当我们使用这个开关编译时,我们可以看到上面的推理不再适用。x - INT_MAX <= 0有可能为假,这样编译器就会生成两个代码路径。

最新更新