有符号整数溢出在c++中仍未定义
Is signed integer overflow still undefined behavior in C++?
我们知道,有符号整数溢出是未定义的行为。但是在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:
typepedef名称
intN_t
指定了一个带符号的整数类型,宽度为N,没有填充位,2的补码表示。因此,int8_t
表示宽度正好为8位的有符号整数类型。
这些类型的溢出仍然是未定义的行为吗?
是的。根据c++ 11标准第5/4段(关于一般表达式):
如果在表达式求值期间,结果没有数学定义或不在的范围内的行为是未定义的。[…]
对于这些有符号类型使用2的补数表示并不意味着在计算这些类型的表达式时使用算术模2^n。
另一方面,对于无符号算术,标准明确规定(第3.9.1/4段):
无符号整数,声明为
特定长度的整数 的值表示形式中的位unsigned
, 服从算术模数2^n,其中n为数字
这意味着无符号算术运算的结果总是"数学定义的",并且结果总是在可表示的范围内;因此,5/4不适用。脚注46解释了这一点:
46)这意味着unsigned算术不会因为结果不能表示的结果而溢出类所能表示的最大值大1的数的模化后的无符号整数类型生成的无符号整数类型。
仅仅因为一个类型被定义为使用2s补码表示,并不意味着该类型中的算术溢出被定义。
有符号算术溢出的未定义行为用于启用优化;例如,编译器可以假设如果a > b
,那么a + 1 > b
也;这在unsigned算术中不成立,因为a + 1
可能会绕到0
,所以需要进行第二次检查。此外,一些平台可以在算术溢出时产生陷阱信号(例如http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html);标准继续允许这种情况发生。
我敢打赌。
来自标准文档(第4页和第5页):
1.3.24未定义行为
本国际标准未规定的行为
[注:当此国际标准时,可能会出现未定义的行为标准省略了对行为或程序何时执行的任何显式定义使用错误的结构或错误的数据。允许定义行为包括从完全忽视情况到不可预测的结果,在翻译或程序过程中的行为以环境特有的文件化方式执行(无论是否发出诊断消息),到终止翻译或执行(带有诊断的发布)消息)。许多错误的程序构造不会产生undefined行为;他们需要被诊断出来。
- 编译C++时未定义的引用
- vscode g++链路故障:体系结构x86_64的未定义符号
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- 未定义的引用在哪里
- 编译时的 CImg 库返回对"__imp_SetDIBitsToDevice"的未定义引用
- 对Py_Initialize()的未定义引用
- c++11评估顺序(未定义的行为)
- 使用mysql c++连接器的未定义引用
- 从python调用openMP共享库时,未定义opnMP函数
- 在 Mac 上使用 CMAKE 将 FFTW 和 FFTWPP 链接到项目中时未定义的符号
- Cmake 链接问题:未定义对 Button::mousePressEvent(QGraphicsSceneMouseE
- 未定义的引用 .. 使用 OpenCV 编译 C++ 代码时,从命令行
- 具有外部"c"和程序集的未定义函数
- 此增量后语句是否会导致未定义的行为?
- 尝试调用 .h 文件中定义的变量时出现变量未定义错误
- 在C++中使用内联方法时出现未定义的符号错误
- 对 Scalar ::Scalar() 的未定义引用