有符号整数溢出在 C + + 中还有未定义行为吗?

但是在 C + + 11 cstdint文档中有一些有趣的东西:

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

看链接

我的问题是: 既然标准明确规定对于 int8_tint16_tint32_tint64_t负数是2的补数,那么这些类型的溢出是否仍然是一种未定义行为?

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

C + + 11,18.4.1:

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

C11,7.20.1.1:

Typedef 名称 intN_t表示带有符号整数类型,宽度为 N,没有填充位,以及一个二的补数表示形式。因此,int8_t表示宽度正好为8位的这种有符号整数类型。

41406 次浏览

I would bet so.

From the standard documentation (pg.4 and 5):

1.3.24 undefined behavior

behavior for which this International Standard imposes no requirements

[ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed.-- end note]

is still overflow of these types an undefined behavior?

Yes. Per Paragraph 5/4 of the C++11 Standard (regarding any expression in general):

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [...]

The fact that a two's complement representation is used for those signed types does not mean that arithmetic modulo 2^n is used when evaluating expressions of those types.

Concerning unsigned arithmetic, on the other hand, the Standard explicitly specifies that (Paragraph 3.9.1/4):

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer

This means that the result of an unsigned arithmetic operation is always "mathematically defined", and the result is always within the representable range; therefore, 5/4 does not apply. Footnote 46 explains this:

46) This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type.

Just because a type is defined to use 2s complement representation, it doesn't follow that arithmetic overflow in that type becomes defined.

The undefined behaviour of signed arithmetic overflow is used to enable optimisations; for example, the compiler can assume that if a > b then a + 1 > b also; this doesn't hold in unsigned arithmetic where the second check would need to be carried out because of the possibility that a + 1 might wrap around to 0. Also, some platforms can generate a trap signal on arithmetic overflow (see e.g. http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html); the standard continues to allow this to occur.