在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 进行了这种更改?