我想知道C/C++位移运算符的正确右操作数是什么。
截至撰写本文时,内置算术类型都少于256位,因此单个字节足够。此外,x86移位指令使用imm8
。这表明右操作数应该是一个unsigned char
,在此处使用不同类型将需要类型转换。
这里是否有“最正确”的类型可用?我知道标准对于位移的其他方面非常宽松,所以也许这是另一种情况?
我想知道C/C++位移运算符的正确右操作数是什么。
截至撰写本文时,内置算术类型都少于256位,因此单个字节足够。此外,x86移位指令使用imm8
。这表明右操作数应该是一个unsigned char
,在此处使用不同类型将需要类型转换。
这里是否有“最正确”的类型可用?我知道标准对于位移的其他方面非常宽松,所以也许这是另一种情况?
任何整数类型都可以用作按位移位运算符的右操作数,只要其值至少为0且小于左操作数的比特长度。
这在C标准关于按位移位运算符的第6.5.7节第2和第3段中有详细规定:
2 每个操作数都必须具有整数类型
3 对每个操作数执行整数提升。结果的类型是提升后的左操作数的类型。如果右操作数的值为负数或大于等于提升后的左操作数的宽度,则行为未定义。
因此,虽然一个unsigned char的范围足以容纳任何有效值,但右操作数将被提升为int。
C语言倾向于将所有东西都作为至少int类型处理,因此如果左移运算符<<和右移运算符>>的右侧指定为unsigned short或unsigned char,则会非常令人惊讶。
很难想象为什么程序员会在那里使用long(或更可怕的是long long),但我刚试了这段代码:
int main()
{
int x = 16;
long int y = 2;
int z1 = x << y;
int z2 = x >> y;
printf("%d %d\n", z1, z2);
long long int y2 = 2;
z1 = x << y2;
z2 = x >> y2;
printf("%d %d\n", z1, z2);
}
我在两个编译器下编译了它,都没有警告,并且两个程序都打印出了64 4
。(虽然不是决定性的测试,但具有启示意义。)
long
或 long long
有任何问题,如果有任何理由要打击它,那么一个高品质的编译器(我尝试了gcc和clang)可能会发出错误。既然两者都没有,那就表明,在这些运算符中使用比 int
更宽的右操作数是没有问题的。 - Steve Summitlong
”:因为他们已经解码了存储在long
中的各种信息,例如(x >> 23 & 0xFF)
,以获取他们想要用作移位量的一些位,之后e >> (x >> 23 & 0xFF)
具有一个long
作为右操作数,只是因为这是在对x
进行操作后得到的结果。 - Eric Postpischil
int
。 - Steve Summitprimary-expression
大约有五到八个级别的差距。是的,有很多路径会导致shift-expression
,所以我认为“宽容”是语法的准确描述。 - Andrew Henleimm8
”:机器指令可能会影响C语言的实现(例如实现对整数类型使用的宽度的选择),但并不是强制性的。使用编译器的主要目的之一是让它生成指令,并且它将生成必要的指令来实现C语义,即使这意味着使用多个指令来完成任务。 - Eric Postpischil