请看下面的代码,为什么文字“1”没有积分提升?
long long n = 50;
long long a = 1 << n; // 262144
long long b = 1LL << n; // 1125899906842624
请看下面的代码,为什么文字“1”没有积分提升?
long long n = 50;
long long a = 1 << n; // 262144
long long b = 1LL << n; // 1125899906842624
根据elazar的要求:
显示的结果是可接受的结果,因为班次调用了未定义的行为。 那是因为平原1
是一个int
,并且将 an 移动一个int
超出范围的值0..(sizeof(int) * CHAR_BIT)-1
(通常,0..31
)会导致未定义的行为。
请注意,移位的类型仅受(提升的)左侧操作数的类型影响。这(正如chris曾经指出的)不同于大多数其他二元运算符,例如加法,其中两个操作数的类型都会影响结果的类型。当然,赋值的类型是由左操作数的类型控制的,如果需要,右边的值会被强制转换为正确的类型(但是赋值右边的值是在不参考它的类型的情况下计算的)将被分配给,如本例所示)。
§6.5.7 移位运算符
¶3对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。
§5.8 移位运算符
操作数应为整数或非范围枚举类型,并执行整数提升。结果的类型是提升的左操作数的类型。
我怀疑你混合了积分提升和通常的算术转换。
积分提升将较小的积分操作数提升到int
或unsigned int
类型。由于1
已经是int
,因此无法进一步提升。
通常的算术转换将二元运算符的操作数转换为通用类型(例如,发生在 binary 的情况下+
),然后用于执行实际计算。我怀疑您希望这些转换发生在您的示例中,因为右侧操作数具有long long
类型。即,您可能希望您1
也可以转换为long long
类型。但是,通常的算术转换根本不针对按位移位运算符执行。它们适用于加法、乘法、关系运算符等,但不适用于位运算符。这就是为什么1
仍然是一个int
并且代码触发未定义行为的原因。
这是一个等效的代码:
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;
现在更清楚了吗?