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

时间:2011-11-24 06:23:04

标签: c++ gcc c++11 bit-shift

以下代码输出0,1,32,33。至少可以说这是违反直觉的。但是,如果我用类型为已声明的常量“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;
    } 

修改  问题:正如Ben所指出的,默认情况下,1被视为32位宽。当它的协同操作数是64位时,为什么不将它提升为64位。

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

从Bill的评论中复制

1 个答案:

答案 0 :(得分:7)

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

1是一个适合int的完整文字。

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

您可能需要(1LL<<k)


标准所说的内容(第5.8节expr.shift):

  

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

与“通常的算术转换”的措辞相反 算术或枚举类型的操作数。“对于例如加法和减法运算符存在。

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