在C ++中有符号整数溢出仍然是未定义的行为吗?

问题描述 投票:68回答:3

我们知道,signed integer overflow is undefined behavior。但是在C ++ 11 cstdint文档中有一些有趣的东西:

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

See link

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

编辑我检查了C ++ 11和C11标准,这是我发现的:

C ++ 11,§18.4.1:

标题定义了所有函数,类型和宏,与C标准中的7.20相同。

C11,§7.20.1.1:

typedef名称intN_t指定一个有符号整数类型,其宽度为N,没有填充位和二进制补码表示。因此,int8_t表示这样的有符号整数类型,其宽度恰好为8位。

c++ c++11 undefined-behavior integer-overflow
3个回答
68
投票

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

是。根据C ++ 11标准的第5/4段(关于任何表达式):

如果在评估表达式期间,结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义。 [...]

将二进制补码表示用于那些有符号类型的事实并不意味着在评估这些类型的表达式时使用算术模2 ^ n。

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

无符号整数,声明为unsigned,应遵守算术模2 ^ n的定律,其中n是整数特定大小的值表示中的位数

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

46)这意味着无符号算术不会溢出,因为无法用结果无符号整数类型表示的结果以比模式生成的无符号整数类型所表示的最大值大1的数量减少。


23
投票

仅仅因为一个类型被定义为使用2s补码表示,它不会遵循该类型中的算术溢出被定义。

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


1
投票

我敢打赌。

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

1.3.24未定义的行为

本国际标准没有要求的行为

[注意:当本国际标准忽略任何明确的行为定义或程序使用错误的构造或错误数据时,可能会出现未定义的行为。允许的未定义行为包括完全忽略不可预测的结果,在翻译或程序执行期间以环境特征(有或没有发出诊断消息)的特定行为,终止翻译或执行(发布)一条诊断信息)。许多错误的程序结构不会产生未定义的行为;他们需要被诊断出来.--最后的说明]

© www.soinside.com 2019 - 2024. All rights reserved.