位操作:类似操作会导致不同的结果

时间:2016-02-24 08:28:15

标签: c++ c operators bit-manipulation

以下这段代码没有评估我认为它应该具有的内容:

#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会有所不同?在执行位移和按位时我做错了什么?

3 个答案:

答案 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。