以下这段代码没有评估我认为它应该具有的内容:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint32_t var = 0x55555555;
uint32_t res1 = (var & (0x3 << (15*2)) >> (15*2));
uint32_t res2 = (var & (0x3 << (14*2)) >> (14*2));
printf("result1 = 0x%08x\n", res1);
printf("result2 = 0x%08x\n", res2);
return 0;
}
输出:
result1 = 0x55555555
result2 = 0x00000001
任何人都可以解释为什么在执行完全相同的操作时result1和result2会有所不同?在执行位移和按位时我做错了什么?
答案 0 :(得分:4)
15 * 2 = 30. 0x3 = 2位 - &gt;在uint32中设置最高位。由于0x3已签名,因此这是一个负数。将其向下移动30位给出0xFFFFFFFFF。当然,如果你将0x3向上移动28位然后再向下移动,也不会发生同样的情况。
如果你真的想分别在31和30以及29和28位选出两位,我会这样做:
uint32_t res1 = (var >> (15*2)) & 0x3;
uint32_t res2 = (var >> (14*2)) & 0x3;
除了“更正确”之外,这也节省了一个班次。
答案 1 :(得分:3)
0x3的类型是signed int。 C标准说:
E1的结果&lt;&lt; E2是E1左移E2位位置;腾出的位用零填充。 [...]如果E1具有有符号类型和非负值,并且E1×2 ^ E2在结果类型中可表示,那么这就是结果值;否则,行为未定义。
0x3 * 2 ^ 30在int中无法表示。
将常量更改为0x3U,您将获得正确的行为。
答案 2 :(得分:3)
在此表达式中
(var & (0x3 << (15*2)) >> (15*2))
整数常量0x3
的类型为int
。在此操作之后
(0x3 << (15*2))
设置结果整数值的符号位。
此操作后
(0x3 << (15*2)) >> (15*2)
实现(它是实现定义的)将符号位传播到右侧。因此,结果表达式的所有位都已设置。
你会得到
var & 0xFFFFFFFF
将产生var
。
在第二个表达式中,符号位未设置且在操作之后
(0x3 << (14*2)) >> (14*2)
您将获得0x3
0x55555555 & 0x3
将产生1。