我们知道,signed integer overflow is undefined behavior。但是在C ++ 11 cstdint
文档中有一些有趣的东西:
有符号整数类型,宽度分别为8,16,32和64位,没有填充位,使用2的补码表示负值(仅当实现直接支持该类型时才提供)
<子> See link 子>
以下是我的问题:由于标准明确指出,对于int8_t
,int16_t
,int32_t
和int64_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位。
答案 0 :(得分:67)
这些类型的溢出仍然是未定义的行为吗?
是。按照C ++ 11标准的第5/4段(关于任何表达方式):
如果在评估表达式期间,结果未在数学上定义或不在范围内 其类型的可表示值,行为未定义。 [...]
对于那些带符号的类型使用二进制补码表示这一事实并不意味着在评估这些类型的表达式时会使用算术模2 ^ n。
另一方面,关于无符号算术,标准明确规定了(第3.9.1 / 4段):
无符号整数,声明为
的值表示中的位数unsigned
,应遵守算术模2 ^ n 的定律,其中n是数字 特定大小整数
这意味着无符号算术运算的结果总是“数学定义”,结果总是在可表示的范围内;因此,5/4不适用。脚注46解释了这一点:
46)这意味着无符号算术不会溢出,因为结果无法表示 无符号整数类型以模数减少,该数字大于可由其表示的最大值 得到无符号整数类型。
答案 1 :(得分:22)
仅仅因为一个类型被定义为使用2s补码表示,它不会跟随该类型中的算术溢出被定义。
带符号算术溢出的未定义行为用于启用优化;例如,编译器可以假设a > b
然后a + 1 > b
;这不适用于无符号算术,因为a + 1
可能会绕回0
,因此需要执行第二次检查。此外,某些平台可以在算术溢出时生成陷阱信号(参见例如http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html);标准继续允许这种情况发生。
答案 2 :(得分:1)
我敢打赌。
从标准文件(第4页和第5页):
1.3.24未定义的行为
本国际标准没有要求的行为
[注意:本国际时可能会出现未定义的行为 标准省略了行为或程序的任何明确定义 使用错误的构造或错误的数据。允许的未定义 行为的范围从完全忽略情况 不可预知的结果,在翻译或程序期间表现 以文件化的方式执行环境特征 (有或没有发出诊断信息),终止 翻译或执行(发布诊断 信息)。许多错误的程序结构不会产生未定义的 行为;他们需要被诊断出来.--最后的注意事项]