86

众所周知,有符号整数溢出是未定义的行为。但是 C++11cstdint文档中有一些有趣的东西:

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

见链接

这是我的问题:由于标准明确规定 for int8_tint16_t和负数是 2 的补码,这些类型的溢出仍然是未定义的行为吗int32_tint64_t

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

C++11,第 18.4.1 节:

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

C11,§7.20.1.1:

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

4

3 回答 3

83

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

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

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

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

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

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

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

46) 这意味着无符号算术不会溢出,因为不能由得到的无符号整数类型表示的结果以比得到的无符号整数类型可以表示的最大值大一的数字为模减少。

于 2013-04-24T09:51:44.553 回答
24

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

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

于 2013-04-24T09:54:59.703 回答
1

我敢打赌。

从标准文档(pg.4 和 5):

1.3.24 未定义的行为

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

[注:当本国际标准省略任何明确的行为定义或程序使用错误的构造或错误数据时,可能会出现未定义的行为。允许的未定义行为的范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(有或没有发出诊断消息),到终止翻译或执行(发出的诊断消息)。许多错误的程序结构不会产生未定义的行为;他们需要被诊断出来。--结束注]

于 2013-04-24T09:39:57.130 回答