代码之家  ›  专栏  ›  技术社区  ›  calebeja9

c理解中的逻辑转换

  •  1
  • calebeja9  · 技术社区  · 7 年前

    我目前正试图理解这种逻辑转变是如何运作的。 根据公式:

    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

    和>&燃气轮机;n到那是 0000 1000 0000 0000 0000 0000 0000 0000

    和(<)<1到那是 0001 0000 0000 0000 0000 0000 0000 0000

    正在执行 mask^ (x>>n) 意味着对执行XOR 0001 0000 0000 0000 0000 0000 0000 0000 0000 0000 具有 0000 1000 0111 0110 0101 0100 0011 0010 这导致 0001 1000 0111 0110 0101 0100 0011 0010 即0x18765432。

    我换档做错了吗?

    3 回复  |  直到 7 年前
        1
  •  2
  •   Antti Haapala -- Слава Україні    7 年前

    此摘录错误:

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

    的行为 x >> 31 什么时候 x 是负数是实现定义的。这个 << 31 如果为负值或符号位发生变化,则符号位具有未定义的行为。它将在非常严格的假设下进行逻辑转换:

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

    这不符合C标准。然而,它在任何GCC目标平台上的行为都会像预期的那样 内景 是32位宽,因为GCC指定最后3位为true。


    这段代码是错误的,因为要进行正确的逻辑移位,应该使用 unsigned 价值观然而,为了得到这些 返回 对有符号的值进行转换是很棘手的,这并不是通常需要的。

    此函数完全定义了逻辑右移的行为,因为 n 在限制范围内(非负且小于 十、 以位为单位):

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

    由于它只执行一个表达式,因此我们注意到不需要为此类操作使用函数。

        2
  •  1
  •   user743382 user743382    7 年前

    是的,你换错了位置。什么时候 >> 的左操作数是有符号整数,编译器通常会执行 算术 右移,不是逻辑右移。函数名中暗示了这一点:if >> 执行了逻辑右移,它可能会返回 x >> n 直接地该函数的要点是通过使用算术右移来实现逻辑右移。

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

    x>&燃气轮机;31是 0000 0000 0000 0000 0000 0000 0000 0001

    x>&燃气轮机;31实际上是 1111 1111 1111 1111 1111 1111 1111 1111

        3
  •  0
  •   Achal    7 年前

    x >> 31 is 0000 0000 0000 0000 0000 0000 0000 0001 不,这是错误的。你的 x signed 整数和 num 0x87654321 这意味着最后 31st bit 1 or set ,所以当你做对的时候 sign 位被复制,结果是 十、 1111 1111 1111 1111 1111 1111 1111 1111

    要获取预期输出,请执行以下操作 数字 unsigned 类型

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

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