为什么是1 < 31改为在C ++ 14中实现定义? [英] Why was 1 << 31 changed to be implementation-defined in C++14?
问题描述
在2014年之前的所有版本的C和C ++中,撰写
In all versions of C and C++ prior to 2014, writing
1 << (CHAR_BIT * sizeof(int) - 1)
引起未定义的行为,因为左移被定义为相当于连续乘以 2
,这个移位会导致有符号整数溢出:
caused undefined behaviour, because left-shifting is defined as being equivalent to successive multiplication by 2
, and this shift causes signed integer overflow:
E1 << E2
是E1
左移E2
空位填充零。 [...]如果E1
有签名类型和非负值,E1
×2 在结果类型中是可表示的,那么这是结果值;
The result of
E1 << E2
isE1
left-shiftedE2
bit positions; vacated bits are filled with zeros. [...] IfE1
has a signed type and nonnegative value, andE1
× 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
但是在C ++ 14中,文本已更改为< <$ / code>但不用于乘法:
However in C++14 the text has changed for <<
but not for multiplication:
E1 < E2
为E1
左移E2
空位是零填充的。 [...]否则,如果E1
有一个有符号类型和非负值,E1
×2 < SUP> E2 可在结果类型的对应的无符号类型中表示,则该值转换为结果类型是结果值;
The value of
E1 << E2
isE1
left-shiftedE2
bit positions; vacated bits are zero-filled. [...] Otherwise, ifE1
has a signed type and non-negative value, andE1
× 2E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.
现在的行为与超出范围的签名类型赋值相同,即:覆盖[conv.integral] / 3:
The behaviour is now the same as for out-of-range assignment to signed type, i.e. as covered by [conv.integral]/3:
如果目标类型是signed,如果它可以在目的地类型(和位域宽度);
If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.
这意味着它仍然是不可移植的 1<< 31
(在具有32位int的系统上)。那么为什么在C ++ 14中进行这种更改呢?
This means it's still non-portable to write 1 << 31
(on a system with 32-bit int). So why was this change made in C++14?
推荐答案
相关问题是 CWG 1457 ,其中的理由是,更改允许 1<< 31
用于常量表达式:
The relevant issue is CWG 1457, where the justification is that the change allows 1 << 31
to be used in constant expressions:
当前的5.8 [expr.shift]它未定义
通过
创建给定类型的最大负整数的行为将一个(signed)1左移到符号位,即使这不是
不常用的并且正常工作在大多数
(二进制补码)架构上:
The current wording of 5.8 [expr.shift] paragraph 2 makes it undefined behavior to create the most-negative integer of a given type by left-shifting a (signed) 1 into the sign bit, even though this is not uncommonly done and works correctly on the majority of (twos-complement) architectures:
...如果E1有一个有符号类型和非负值,并且E1 * 2 E2 是
在结果类型中可表示,那么它是结果值;
否则,行为是未定义的。
...if E1 has a signed type and non-negative value, and E1 * 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
因此,此技术
不能用于常量表达式,这将破坏
代码量。
As a result, this technique cannot be used in a constant expression, which will break a significant amount of code.
常量表达式不能包含未定义的行为,这意味着在上下文中使用包含UB的表达式,表达式使程序不成形。 libstdc ++的 numeric_limits :: min
,例如,一旦失败由于这个原因,在clang 中编译。
Constant expressions can't contain undefined behavior, which means that using an expression containing UB in a context requiring a constant expression makes the program ill-formed. libstdc++'s numeric_limits::min
, for example, once failed to compile in clang due to this.
这篇关于为什么是1 < 31改为在C ++ 14中实现定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!