奇怪的积分提升用左移运算符

Weird integral promotions with left shift operator

本文关键字:左移 运算符      更新时间:2023-10-16

请参阅下面的代码,为什么文字"1"没有积分提升?

long long n = 50;
long long a = 1 << n; // 262144
long long b = 1LL << n; // 1125899906842624

按elazar的要求:

显示的结果是一个可接受的结果,因为移位调用了未定义的行为。这是因为普通的1int,而将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;

现在更清楚了吗?

我怀疑你混合了积分提升通常的算术转换

积分提升将较小的积分操作数提升为intunsigned int类型。因为1已经是int了,所以不能再提升了。

通常的算术转换将二进制操作符的操作数转换为公共类型(例如,就像二进制+的情况一样),然后使用它来执行实际的计算。我怀疑您希望在示例中发生这些转换,因为右操作数具有long long类型。也就是说,你可能希望你的1转换为long long类型。然而,对于位移位操作符,通常的算术转换是不执行的。它们适用于加法、乘法、关系操作符等,但不适用位操作符。这就是为什么1仍然是int并且代码触发未定义行为的原因。