为什么`1 << 32`和`int i=32; 1 << i`的结果不同?这是一个 bug 还是 feature?

3
代码如下。我在VS、clang++和G++上进行了测试,所有这些编译器都显示1 << 321 << i(其中i为32)是不同的。我查看了汇编代码,似乎编译器在编译时计算1 << 32的结果。我认为这种不一致应该是一个bug或者只是C++的另一个未定义行为。
#include <iostream>

int main(int argc, char *argv[])
{
    std::cout << (1 << 32) << std::endl;
    int i = 32;
    std::cout << (1 << i) << std::endl;
    return 0;
}

结果:

clang++:
1 << 32:73832
1 << i:1
g++:
1 << 32:73832
1 << i:1

9
你说它会产生不同的结果,但却没有展示这些结果。 - ForceBru
请查看警告 - πάντα ῥεῖ
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Yyao
那么你得到了哪些结果? - Antti Haapala -- Слава Україні
@ForceBru 我添加了结果。 - Yyao
3个回答

8

std::cout << (1 << 32) << std::endl;

如果您的系统上int是4个字节,则此操作为未定义行为。根据标准(关于移位运算符的部分):

结果的类型是左操作数提升后的类型。如果右操作数为负数或大于等于左操作数提升后的长度(以位为单位),则其行为未定义。


3

C++标准规定:

E1 << E2 的值是将 E1 左移 E2 个二进制位,空出的位填充为零。如果 E1 是无符号类型,则结果的值为 E1×2^E2,对比结果类型能表示的最大值加一取模后的余数。否则,如果 E1 是有符号类型且非负值,且 E1×2^E2 能在结果类型中表示,则该值为结果;否则,行为未定义

然后:

结果的类型是左操作数提升后的类型。如果右操作数为负数或大于等于左操作数提升后的长度(以位为单位),则行为未定义

在这种情况下,你不应该期望得到任何好的结果。


2
<<的两个操作数都是int类型,因此结果也是int类型。如果int最大为32位,则两种情况下都会发生有符号整数溢出;有符号整数溢出在C和C++中始终具有未定义行为。
然而,许多人错误地认为未定义行为意味着结果是某个“未指定的int”或者在他们的平台上结果是1 << 32 (mod 2³²);但事实上,在64位平台上编译器往往会对32位计算使用64位寄存器,因为它们知道在符合规范的程序中计算永远不会溢出,所以在未定义行为的情况下,实际结果可能是一个甚至不适合32位变量的值!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接