位移编译器错误或角落案例?

rpg*_*rpg 5 c++ gcc bit-shift c++11

以下代码输出0,1,32,33.至少可以说这是违反直觉的.但是如果我用类型annonated constant"ONE"替换文字1,循环运行正常.

这是使用gcc 4.6.2和-std = c ++ 0x.

#include<iostream>
#include<cstdint>
using namespace std;
int main()
    {
    int64_t bitmask = 3;
    int64_t k;
    const int64_t ONE = 1;
    cout<<"bitmask = "<<bitmask<<endl;

    for(k=0; k<64; k++)
        {
        if(bitmask & (1<<k))
            {
            cout<<"k="<<k<<endl;
            }
        }

    return 0;
    } 
Run Code Online (Sandbox Code Playgroud)

编辑 问题:正如Ben指出的那样,默认情况下,1被视为32位宽.当它的协同操作数是64位时,为什么它不会被提升为64位.

没有.<<不要求每一方都有相同的类型.毕竟,为什么当可用的最大移位适合char时,右侧是int64_t?促销仅在您处理算术运算符而非所有运算符时发生.

复制自Bill的评论如下

Ben*_*igt 7

这是一个问题:(1<<k).

1是一个完整的文字,适合于int.

如果int您的平台上的位数少于64位,那么(1<<k)在循环结束时会有大量未定义的行为k.在您的情况下,编译器使用Intel bitshift指令,并且未定义的行为以Intel定义的移位大于操作数大小的方式出现 - 高位被忽略.

你可能想要 (1LL<<k)


标准说的是什么(第5.8节expr.shift):

操作数应为整数或无范围的枚举类型,并执行整体促销.结果的类型是提升的左操作数的类型.如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义.

这与"通常的算术转换是针对算术或枚举类型的操作数执行"的措辞形成对比.这对于例如加法和减法运算符而言是存在的.

这种语言在C++ 03和C++ 11之间没有变化.