1

请看下面的代码,为什么文字“1”没有积分提升?

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

3 回答 3

12

根据elazar的要求:

显示的结果是可接受的结果,因为班次调用了未定义的行为。 那是因为平原1是一个int,并且将 an 移动一个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 移位运算符

操作数应为整数或非范围枚举类型,并执行整数提升。结果的类型是提升的左操作数的类型。

于 2013-06-02T06:16:27.533 回答
3

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

积分提升将较小的积分操作数提升到intunsigned int类型。由于1已经是int,因此无法进一步提升。

通常的算术转换将二元运算符的操作数转换为通用类型(例如,发生在 binary 的情况下+),然后用于执行实际计算。我怀疑您希望这些转换发生在您的示例中,因为右侧操作数具有long long类型。即,您可能希望您1也可以转换为long long类型。但是,通常的算术转换根本不针对按位移位运算符执行。它们适用于加法、乘法、关系运算符等,但不适用于位运算符。这就是为什么1仍然是一个int并且代码触发未定义行为的原因。

于 2013-06-02T06:52:09.003 回答
2

这是一个等效的代码:

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;

现在更清楚了吗?

于 2013-06-02T06:04:06.267 回答