C整数溢出

lstz6jyr  于 2023-10-16  发布在  其他
关注(0)|答案(4)|浏览(87)

我在C中使用整数,试图探索更多关于何时以及如何发生溢出的信息。
我注意到,当我把两个正数相加时,其和溢出,我总是得到一个负数。
另一方面,如果我把两个负数相加,其和溢出,我总是得到一个正数(包括0)。
我做了一些实验,但我想知道这是否对每一个案例都是正确的。

ao218c7q

ao218c7q1#

在C语言中,溢出是未定义的行为。
C说一个涉及整数的表达式 * 溢出 *,如果它在通常的算术转换之后的结果是有符号类型的,并且不能用结果的类型表示。赋值和强制转换表达式是一个例外,因为它们由整数转换控制。
无符号类型的表达式不能溢出;例如,0U - 1UINT_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

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

a - 10 < 20

a在升级后是int类型时,表达式在gcc中减少(当启用优化时)为:

a < 30

它利用了当aINT_MIN + 10 - 1INT_MIN的范围内时表达式的未定义行为。
aunsigned int时,无法进行此优化,因为如果a0,则a - 10必须被评估为UINT_MAX - 9(没有未定义的行为)。优化a - 10 < 20a < 30将导致与a09时所需的结果不同的结果。

wgxvkvu9

wgxvkvu92#

有符号整数的溢出在C中是未定义的行为,因此没有保证。
也就是说,回绕或算术模2N,其中N是类型中的位数,是一种常见的行为。对于这种行为,实际上,如果一个和溢出,结果具有相反的符号的操作数。

lokaqttq

lokaqttq3#

形式上,有符号算术在溢出时的行为是未定义的;任何事情都可能发生,而且是“正确的”。这与无符号算术相反,后者完全定义了溢出。
在实践中,许多旧的编译器使用带符号的算术,如你所描述的那样溢出。然而,现代GCC正在改变它的工作方式,依赖这种行为是非常不明智的。当编译代码的环境中的任何东西发生变化时,它可能会随时发生变化-编译器,平台...

0s7z1bwu

0s7z1bwu4#

C中的Overflow是一个可怕的混乱。

  • 无符号算术或转换为无符号类型期间的溢出将导致以2n为模进行换行
  • 在转换到有符号类型的过程中溢出是实现定义的,大多数实现将 Package 模2n,但有些可能不会。
  • 在有符号算术中溢出是未定义的行为,根据标准,任何事情都可能发生。在实践中,有时它会做你不想做的事情,有时它会在编译器优化重要测试时在你的代码中引起奇怪的问题。

更糟糕的是这与整数提升的交互方式。多亏了推广,你可以在看起来像是在做无符号算术的时候做有符号算术。例如,考虑以下代码

uint16_t a = 65535;
uint16_t b = a * a;

在16位int的系统上,这段代码是定义良好的。然而,在一个32位int的系统上,乘法将以有符号int的形式发生,产生的溢出将是未定义的行为!

相关问题