有符号整数溢出在c++中仍未定义

Is signed integer overflow still undefined behavior in C++?

本文关键字:未定义 c++ 符号 整数 溢出      更新时间:2023-10-16

我们知道,有符号整数溢出是未定义的行为。但是在c++ 11 cstdint文档中有一些有趣的东西:

有符号整数类型,宽度分别为8,16,32和64位,没有填充位,使用2的补码对负值(仅在实现直接支持该类型时提供)

<子>看到链接

我的问题是:既然标准明确规定,对于int8_t, int16_t, int32_tint64_t的负数是2的补码,那么这些类型的溢出仍然是未定义的行为吗?

编辑我检查了c++ 11和C11标准,下面是我发现的:

c++ 11日§18.4.1:

头文件定义了与C标准7.20相同的所有函数、类型和宏。

C11,§7.20.1.1:

typepedef名称intN_t指定了一个带符号的整数类型,宽度为N,没有填充位,2的补码表示。因此,int8_t表示宽度正好为8位的有符号整数类型。

这些类型的溢出仍然是未定义的行为吗?

是的。根据c++ 11标准第5/4段(关于一般表达式):

如果在表达式求值期间,结果没有数学定义或不在的范围内的行为是未定义的。[…]

对于这些有符号类型使用2的补数表示并不意味着在计算这些类型的表达式时使用算术模2^n。

另一方面,对于无符号算术,标准明确规定(第3.9.1/4段):

无符号整数,声明为unsigned服从算术模数2^n,其中n为数字

特定长度的整数 的值表示形式中的位

这意味着无符号算术运算的结果总是"数学定义的",并且结果总是在可表示的范围内;因此,5/4不适用。脚注46解释了这一点:

46)这意味着unsigned算术不会因为结果不能表示的结果而溢出类所能表示的最大值大1的数的模化后的无符号整数类型生成的无符号整数类型。

仅仅因为一个类型被定义为使用2s补码表示,并不意味着该类型中的算术溢出被定义。

有符号算术溢出的未定义行为用于启用优化;例如,编译器可以假设如果a > b,那么a + 1 > b也;这在unsigned算术中不成立,因为a + 1可能会绕到0,所以需要进行第二次检查。此外,一些平台可以在算术溢出时产生陷阱信号(例如http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html);标准继续允许这种情况发生。

我敢打赌。

来自标准文档(第4页和第5页):

1.3.24未定义行为

本国际标准未规定的行为

[注:当此国际标准时,可能会出现未定义的行为标准省略了对行为或程序何时执行的任何显式定义使用错误的结构或错误的数据。允许定义行为包括从完全忽视情况到不可预测的结果,在翻译或程序过程中的行为以环境特有的文件化方式执行(无论是否发出诊断消息),到终止翻译或执行(带有诊断的发布)消息)。许多错误的程序构造不会产生undefined行为;他们需要被诊断出来。