【发布时间】:2014-12-07 11:44:46
【问题描述】:
在 2014 年之前的所有 C 和 C++ 版本中,写作
1 << (CHAR_BIT * sizeof(int) - 1)
导致未定义的行为,因为左移被定义为等同于连续乘以2,并且这种移位导致有符号整数溢出:
E1 << E2的结果是E1左移E2位位置;空出的位用零填充。 [...] 如果E1具有带符号类型和非负值,并且E1× 2E2 在结果类型中是可表示的,那么这就是结果值;否则,行为未定义。
但在 C++14 中,<< 的文本已更改,但乘法却没有:
E1 << E2的值是E1左移E2位位置;空出的位用零填充。 [...] 否则,如果E1具有带符号类型和非负值,并且E1× 2E2 可以表示为 对应的无符号类型结果类型,然后那个值,转换为结果类型,就是结果值;否则,行为未定义。
现在的行为与对有符号类型的超出范围分配相同,即由 [conv.integral]/3 涵盖:
如果目标类型是有符号的,如果它可以在目标类型(和位域宽度)中表示,则值不变;否则,值是实现定义的。
这意味着写1 << 31 仍然是不可移植的(在具有 32 位 int 的系统上)。那么为什么要在 C++14 中做出这种改变呢?
【问题讨论】:
-
+1 Howard Hinnant comments on this topic here,我记得这条评论的唯一原因是这条评论是我对 question 的灵感的一部分。
-
想象一下,如果他们只是简单地陈述了以下内容:“约束:提升后,左操作数 E1 应为无符号整数类型”。它将人类从数量惊人的与转变相关的微妙错误中拯救出来。