-2

任何人都可以帮助我理解以下行为。

    1    #include <iostream>
    2
    3    using namespace std;
    4
    5    main()
    6    {
    7        uint32_t i = 32;
    8
    9        // cout << "(1<<32): " << (1<<32) << endl; // - This leads to a compilation error.
    10       cout << "(1<<32): " << (1<<i) << endl; // - This compiles and prints 1 - Why?
    11
    12        return 0;
    13    }

如果我取消注释上面的第 9 行 - 我会看到以下编译错误(这对我来说很有意义)

BitWiseLeftShift.c++: In function 'int main()':
BitWiseLeftShift.c++:9: warning: left shift count >= width of type

但是第 10 行是我的问题所在。它编译成功并打印

(1<<32): 1

类似于循环位移。为什么会打印 1?我已经看到了i == 33(1<<i)打印 2。

我确实搜索了论坛,但找不到相关问题。如果这是一个重复的问题 - 请帮助我提供链接。


正如其他答案所指出的,如果移位量大于或等于移位数据的大小(或为负),则结果未定义。

但是,为了解释您所看到的行为 -

一些计算机体系结构(包括 x86)将移位量视为要移位的数据大小的模数,因此移位 32 相当于根本不移位。换句话说,他们只是屏蔽了高位并使用低位。

4

4 回答 4

7

这些转变是不合法的,但编译器只捕获第一个:

6.5.7

对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。

于 2013-01-20T10:11:46.777 回答
5

正如其他答案所指出的,如果移位量大于或等于移位数据的大小(或为负),则结果未定义。

但是,为了解释您所看到的行为 -

一些计算机体系结构(包括 x86)将移位量视为要移位的数据大小的模数,因此移位 32 相当于根本不移位。换句话说,他们只是屏蔽了高位并使用低位。

于 2013-01-20T10:11:21.067 回答
4

首先,这不是错误,而是警告。编译器在第二种情况下没有警告的原因是它可能不够聪明,无法从第一个赋值中推断出结果将是未定义的行为,而在第一种情况下,常量左移 32 位是“显然”是编译器捕获的问题。

于 2013-01-20T10:12:37.087 回答
1

常量移位由前处理器在常量折叠期间评估,而第二个移位由大多数编译器推迟到运行时。这将解释编译器连续传递的不同响应。

使用静态分析可以确定两者确实具有相同的结果并且可以在编译期间检测到。

于 2013-01-20T10:29:35.090 回答