Arc*_*hie 74 c++ integer-overflow undefined-behavior c++11
众所周知,有符号整数溢出是未定义的行为.但是C++ 11 cstdint
文档中有一些有趣的东西:
有符号整数类型,宽度分别为8,16,32和64位,没有填充位,负值使用2的补码(仅当实现直接支持该类型时提供)
这里是我的问题:由于标准明确地说,对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位.
And*_*owl 70
仍然是这些类型的溢出未定义的行为?
是.根据C++ 11标准的第5/4段(关于任何表达式):
如果在评估表达式期间,结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义.[...]
将二进制补码表示用于那些有符号类型的事实并不意味着在评估这些类型的表达式时使用算术模2 ^ n.
另一方面,关于无符号算术,标准明确规定(第3.9.1/4段):
无符号整数,声明
unsigned
,应当服从算术模的法律2 ^ N,其中n是比特的整数的特定大小的值表示的数目
这意味着无符号算术运算的结果总是" 数学定义 ",结果总是在可表示的范围内; 因此,5/4不适用.脚注46解释了这一点:
46)这意味着无符号算术不会溢出,因为无法用结果无符号整数类型表示的结果是以比可以由结果无符号整数类型表示的最大值大1的数量减少的模数.
eca*_*mur 23
仅仅因为一个类型被定义为使用2s补码表示,它不会遵循该类型中的算术溢出被定义.
带符号算术溢出的未定义行为用于启用优化; 例如,编译器可以假设如果a > b
那么a + 1 > b
; 这不无符号运算,其中第二检查需要的,因为这有可能要进行持有a + 1
可能环绕到0
.此外,一些平台可以在算术溢出时生成陷阱信号(参见例如http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html); 标准继续允许这种情况发生.