位运算:相似运算结果不同

Bit operation: Similar operation results in different results

以下这段代码没有计算出我认为它应该具有的值:

#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;
}

输出:

结果 1 = 0x55555555

结果 2 = 0x00000001

谁能解释为什么在执行完全相同的操作时 result1 和 result2 会不同?我在执行位移和位与时做错了什么?

15 *2 = 30。0x3 = 2 位 -> 设置 uint32 中的最高位。因为 0x3 是有符号的,所以这是一个负数。将其向下移动 30 位得到 0xFFFFFFFFF。当然,如果将 0x3 向上移动 28 位然后再次向下移动,则不会发生同样的情况。

如果你真的想分别在位 31&30 和位 29&28 中挑出两位,我会这样做:

uint32_t res1 = (var >> (15*2)) & 0x3;
uint32_t res2 = (var >> (14*2)) & 0x3;

除了"more correct"。

这也节省了一个班次

0x3的类型是signed int。 C 标准说:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed type and nonnegative value, and E1 × 2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

0x3 * 2^30 不能用整数表示。

将常量更改为 0x3U,您将得到正确的行为。

在这个表达式中

(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。