理解中的逻辑转变

时间:2018-04-15 09:46:44

标签: c bit-manipulation bit-shift

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

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&gt;&gt; 31是0000 0000 0000 0000 0000 0000 0000 0001

和&lt;&lt; 31到那是1000 0000 0000 0000 0000 0000 0000 0000

和&gt;&gt;那是0000 1000 0000 0000 0000 0000 0000 0000

和&lt;&lt; 1到那是0001 0000 0000 0000 0000 0000 0000 0000

执行mask^ (x>>n)表示使用0001 0000 0000 0000 0000 0000 0000 00000000 1000 0111 0110 0101 0100 0011 0010执行XOR,结果为0001 1000 0111 0110 0101 0100 0011 0010,即0x18765432。

我做错了吗?

3 个答案:

答案 0 :(得分:2)

这段摘录错了:

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

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

  • int的宽度为32位
  • 签名整数有2个补码作为其内部表示
  • 负数右移的行为算术右移
  • 将负数左移的行为定义为2的补码表示在逻辑上向左移动。

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

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

此函数已完全定义逻辑右移的行为,因为x的值在限制范围内(非负数且小于unsigned int logicalShift(unsigned int x, int n) { return x >> n; } 的宽度(以位为单位)):

saveClientToDatabase

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

答案 1 :(得分:1)

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

什么算术右移意味着当右移时,左边的位没有用零填充,而是用最左边的位(符号位)填充。因此:

  

x&gt;&gt; 31是0000 0000 0000 0000 0000 0000 0000 0001

x&gt;&gt; 31实际上是1111 1111 1111 1111 1111 1111 1111 1111

答案 2 :(得分:0)

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)会被复制到剩余的字节中,如果它的逻辑右移,那么它就不会。