c理解的逻辑转变

logical shift in c understanding

我目前正在尝试理解这种逻辑转变是如何运作的。 给定公式:

int logicalShift(int x, int n){
    int mask = x >> 31 << 31 >> n << 1;
    return mask^ (x>>n);
}

x = 0x87654321 and n = 4. 的测试 运行 给出了 logicalShift(x,n) = 0x08765432

在这里,我知道 x 在二进制中是 1000 0111 0110 0101 0100 0011 0010 0001 并且在掩码过程之后,

x >> 31 是 0000 0000 0000 0000 0000 0000 0000 0001

<< 31 就是 1000 0000 0000 0000 0000 0000 0000 0000

and >> n 就是 0000 1000 0000 0000 0000 0000 0000 0000

并且 << 1 是 0001 0000 0000 0000 0000 0000 0000 0000

mask^ (x>>n) 意味着用 0000 1000 0111 0110 0101 0100 0011 00100001 0000 0000 0000 0000 0000 0000 0000 进行异或运算,结果是 0001 1000 0111 0110 0101 0100 0011 0010,即 0x18765432.

我换档错了吗?

x >> 31 is 0000 0000 0000 0000 0000 0000 0000 0001不对,错了。你的 xsigned 整数而 num0x87654321 这意味着最后一个 31st bit1 or set,所以当你右移 sign 位被复制,结果 x1111 1111 1111 1111 1111 1111 1111 1111

要获得预期的输出,请将 num 作为 unsigned 类型。

int logicalShift(unsigned int x, int n){
   /* some code */
}

请注意,它的实现依赖于如果你的处理器支持算术右移然后last bit(sign bit)被复制到剩余的字节,如果它是逻辑右移那么它不会'吨。

是的,你做错了。当 >> 的左操作数是有符号整数时,编译器通常会执行 算术 右移,而不是逻辑右移。这在函数名称中有所暗示:如果 >> 执行逻辑右移,它可以直接 return x >> n。该函数的要点是通过算术右移来实现逻辑右移。

算术右移的意思是右移时,左边的位不补零,而是补最左边的位(符号位)。因此:

x >> 31 is 0000 0000 0000 0000 0000 0000 0000 0001

x >> 31 实际上是 1111 1111 1111 1111 1111 1111 1111 1111.

这段摘录是错误的:

int logicalShift(int x, int n){
    int mask = x >> 31 << 31 >> n << 1;
    return mask^ (x>>n);
}

x 为负时 x >> 31 的行为是实现定义的。 << 31 具有负值或如果它更改符号位具有未定义的行为。它会像在非常严格的假设下进行逻辑移位一样工作:

  • int的宽度是32位
  • 有符号整数以 2 的补码作为其内部表示
  • 负数右移的行为算术右移,
  • 负数左移的行为定义为 2 的补码表示逻辑左移。

这不符合 C 标准。但是,它在 int 为 32 位宽的任何 GCC 目标平台上的行为都符合预期,因为 GCC 将最后 3 个指定为真。


这段代码是错误的,因为要进行正确的逻辑移位,应该使用 unsigned 值。但是,要将这些 返回 为有符号值是很棘手的 - 通常不需要它。

鉴于 n 的值在限制范围内(非负且小于 x 的位宽度),此函数具有完全定义的逻辑右移行为:

unsigned int logicalShift(unsigned int x, int n) {
    return x >> n;
}

因为它只做一个表达式,我们注意到不需要为这样的操作使用函数。