奇怪的积分提升用左移运算符
Weird integral promotions with left shift operator
请参阅下面的代码,为什么文字"1"没有积分提升?
long long n = 50;
long long a = 1 << n; // 262144
long long b = 1LL << n; // 1125899906842624
按elazar的要求:
显示的结果是一个可接受的结果,因为移位调用了未定义的行为。这是因为普通的1
是int
,而将int
移到0..(sizeof(int) * CHAR_BIT)-1
(通常是0..31
)范围之外的值会导致未定义的行为。
请注意,移位的类型仅受(提升的)左操作数类型的影响。这与大多数其他二进制操作符(如加法)不同(正如chris曾经指出的那样),在加法中,两个操作数的类型都会影响结果的类型。当然,赋值操作的类型是由左操作数的类型控制的,如果有必要,右边的值会被强制转换为正确的类型(但是,在计算赋值操作时,右边的值不会引用它将被赋给的类型,如本例所示)。
ISO/IEC 9899:2011 (C)
§6.5.7位移运算符
¶3对每个操作数执行整数提升。的结果的类型是提升后的左操作数的类型。如果右操作数的值为负或大于等于提升后的左操作数的宽度,则未定义该行为。
ISO/IEC 14822:2011 (c++)
§5.8移位运算符
操作数必须为整型或无作用域枚举类型,并执行整型提升。操作结果的类型为提升后的左操作数的类型。
等效代码:
long long n = 50;
int x = 1;
x <<= n; // sizeof(x) is 4, probably. 32 bit. we are shifting it by 50.
long long a = x;
long long z = 1LL;
z <<= n;
long long b = z;
现在更清楚了吗?
我怀疑你混合了积分提升和通常的算术转换。
积分提升将较小的积分操作数提升为int
或unsigned int
类型。因为1
已经是int
了,所以不能再提升了。
通常的算术转换将二进制操作符的操作数转换为公共类型(例如,就像二进制+
的情况一样),然后使用它来执行实际的计算。我怀疑您希望在示例中发生这些转换,因为右操作数具有long long
类型。也就是说,你可能希望你的1
转换为long long
类型。然而,对于位移位操作符,通常的算术转换是不执行的。它们适用于加法、乘法、关系操作符等,但不适用位操作符。这就是为什么1
仍然是int
并且代码触发未定义行为的原因。
相关文章:
- 使用boost::multiprecision cpp_int左移时出现超时错误
- 警告:左移计数 >= 在 C++ 中将字节流读取为双精度变量时的类型宽度
- 左移<<如何在不同的功能中给出不同的结果?
- 使用 AVX2 指令左移 128 位数字
- <<(按位左移)在 Swift 中的数组上做什么?
- 带有左移操作员C 的意外输出
- 编译器将输出的流运算符<<解释为用于按位左移的二进制运算符<<
- 左移负整数为零是否有意义?
- 在 VS 移位中,UINT64 上的左移(64 >移位> 32)位仅 32 位
- C++20 是否为"overflow"的有符号整数很好地定义了左移?
- C++左移操作
- 为什么编译器左移 0
- 如何在位明智的操作中选择正确的左移
- 虽然左移运算符 (<<) 在 std::cout 之前使用,但它有什么用?
- 使用左移运算符将 F 转换为 FF
- 重载左移和右移运算符(cin和cout)
- 重载运算符'<<'(左移)的显式专用化
- 奇怪的积分提升用左移运算符
- 何时使用运算符<<指插入运算符,何时指按位左移
- 测试左移运算符是否存在