以下代码输出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的评论中复制
答案 0 :(得分:7)
这是一个问题:(1<<k)
。
1
是一个适合int
的完整文字。
如果您的平台上int
少于64位,那么当(1<<k)
很大时,k
将在循环结束时具有未定义的行为。在您的情况下,编译器使用Intel bitshift指令,并且未定义的行为以Intel定义的移位大于操作数大小的方式出现 - 高位被忽略。
您可能需要(1LL<<k)
标准所说的内容(第5.8节expr.shift
):
操作数应为整数或无范围的枚举类型,并执行整体促销。结果的类型是提升的左操作数的类型。如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义。
与“通常的算术转换”的措辞相反 算术或枚举类型的操作数。“对于例如加法和减法运算符存在。
这种语言在C ++ 03和C ++ 11之间没有变化。