在C++中有符号整数溢出仍然是未定义的行为吗?

Arc*_*hie 74 c++ integer-overflow undefined-behavior c++11

众所周知,有符号整数溢出是未定义的行为.但是C++ 11 cstdint文档中有一些有趣的东西:

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

见链接

这里是我的问题:由于标准明确地说,对int8_t,int16_t,int32_tint64_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的数量减少的模数.

  • @Archie:不是,因为无符号值被定义为_modulo_无符号范围. (7认同)
  • @Archie:我试着澄清一下,但基本上你得到了LightnessRacesinOrbit的答案 (3认同)
  • 有一些无符号运算的结果不是“数学定义的”——尤其是除以零——所以也许你的措辞与你在这句话中的意思不完全一样。ITYM *当结果以数学方式定义时*,那么它也在 C++ 中定义。 (2认同)

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); 标准继续允许这种情况发生.

  • 值得注意的是,许多人"更担心"陷阱的可能性,但编译器假设实际上更加隐蔽(我希望实现定义和未定义行为之间存在类别的原因之一 - 与实现定义的行为不同这需要特定的实现以一致的文档化方式执行某些操作,我想要一个"实现受限"的行为,这需要实现来指定可能由于某些事情而发生的一切(规范可能明确包含未定义的行为,但是...... . (4认同)
  • ......实际上鼓励实施更具体.)在二进制补码数会自然"包裹"的硬件上,没有明智的理由要求包装整数结果执行许多指令,试图在没有整数溢出的情况下执行计算,硬件可以在一两个指令中执行. (3认同)