C 整数溢出

Fra*_*nXh 1 c integer overflow

我在 C 中处理整数,试图更多地探索溢出发生的时间和方式。

我注意到当我添加两个正数时,它们的总和溢出,我总是得到一个负数。

另一方面,如果我添加两个负数,它们的总和溢出,我总是得到一个正数(包括 0)。

我做了一些实验,但我想知道这是否适用于每种情况。

oua*_*uah 7

整数溢出是 C 中未定义的行为。

C 说一个涉及整数的表达式溢出,如果它在通常的算术转换之后的结果是有符号类型的并且不能用结果的类型表示。赋值和强制转换表达式是一个例外,因为它们受整数转换的约束。

无符号类型的表达式不能溢出,它们会换行,例如0U - 1is UINT_MAX

例子:

INT_MAX + 1    // integer overflow
UINT_MAX + 1   // no overflow, the resulting type is unsigned
(unsigned char) INT_MAX // no overflow, integer conversion occurs 
Run Code Online (Sandbox Code Playgroud)

永远不要让任何整数表达式溢出,现代编译器(如gcc)利用整数溢出作为未定义行为来执行各种类型的优化。

例如:

a - 10 < 20
Run Code Online (Sandbox Code Playgroud)

whenaint提升后的类型,表达式在gcc(启用优化时)减少为:

a < 30
Run Code Online (Sandbox Code Playgroud)

aINT_MIN + 10 - 1to范围内时,它利用表达式是未定义的行为INT_MIN

ais时无法进行此优化,unsigned int因为如果a0,则a - 10必须将其评估为UINT_MAX - 9(无未定义行为)。优化a - 10 < 20a < 30那么将导致不同的结果,当需要的一个a09


Jon*_*ler 5

形式上,有符号算术在溢出时的行为是未定义的;任何事情都可能发生,而且它是“正确的”。这与无符号算术形成对比,后者完全定义了溢出。

\n\n

在实践中,许多较旧的编译器使用有符号算术,如您所描述的那样会溢出。然而,现代 GCC 正在改变它的工作方式,你依赖这种行为是非常不明智的。当编译代码的环境中的任何内容发生变化时,它可能随时发生变化 \xe2\x80\x94 编译器、平台......

\n

  • 相关:在他的博客文章[未定义的行为可能导致时间旅行](https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633)中,微软开发人员 Raymond Chen 将这种类型的优化与他的优化进行了比较。调用_经典编译器_和_后经典_或_后现代编译器_。所以,是的,编译器的行为在这方面确实发生了变化。 (2认同)