在C99中有一些(可选)类型,如int8_t
,int16_t
等,它们保证具有精确指定的宽度并且没有填充位,并表示二进制补码(7.18.1.1)中的数字。在6.2.6.2中,有符号整数溢出被提及为脚注44)和45),即它可能导致在填充位中捕获值。
由于intN_t
没有任何填充位,并且它们保证是两个的补充,这是否意味着它们的溢出不会产生任何未定义的行为?例如溢出乘法的结果是什么?加法呢?结果是否减少了无符号类型的模2^N
?
注不是规范性的。如果脚注指出溢出会导致在填充位中捕获值,那并没有真正错误,但我可以看到它有点误导。规范性文本只是说行为是未定义的。将陷印值放在填充位中是未定义行为的一个可能结果,但不是唯一的结果。
所以不,这并不意味着定义了溢出。涉及 intN_t
/uintN_t
操作数的操作数可能会溢出,并且溢出可能会导致未定义的行为。
像int8_t i = 127; ++i;
这样的东西没有 UB。 int8_t
受到整体促销的影响,因此添加就像您写了i = (int8_t) ((int) i + 1);
一样进行。添加本身不会溢出,并且转换回int8_t
会产生实现定义的结果。
像uint16_t u = 65535; u *= u;
这样的东西在当前的典型实现中具有UB,其中int
具有32个符号/值位。 uint16_t
也受到积分提升的影响,因此乘法就像您写了u = (uint16_t) ((int) u * (int) u);
一样进行。乘法本身溢出,并且行为未定义。
像int64_t i = 9223372036854775807; ++i;
这样的东西在几乎所有的实现上都有UB。添加本身溢出。
不,它没有很好地定义,因为...它根本没有定义。标准中根本没有文本可以为有符号整数的溢出提供语义。
不要过分强调"未定义的行为"一词是神秘的,而是要直接理解它。没有行为的定义,因此标准没有指定应该发生的任何情况,并且任何可移植代码都不应依赖于此类功能。