为什么是1 < 31改为在C ++ 14中实现定义? [英] Why was 1 &lt;&lt; 31 changed to be implementation-defined in C++14?

查看:162
本文介绍了为什么是1 < 31改为在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 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed type and nonnegative value, and E1 × 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 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. [...] Otherwise, if E1 has a signed type and non-negative value, and E1 × 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆