位移是否取决于字节序?

时间:2011-08-25 03:21:57

标签: c endianness

假设我有数字'numb'=1025 [00000000 00000000 00000100 00000001]

在Little-Endian机器上:

00000001 00000100 00000000 00000000

在Big-Endian机器上:

00000000 00000000 00000100 00000001

现在,如果我在10位上应用左移(即:numb<< = 10),我应该:

[A]在Little-Endian机器上:

正如我在GDB中所注意到的,Little Endian通过3个步骤执行左移:[我已经显示'3'步骤以更好地理解处理]

  1. 对待不。在Big-Endian公约中:

    00000000        00000000        00000100    00000001
    
  2. 应用左移:

    00000000        00010000        00000100        00000000
    
  3. 再次在Little-Endian中表示结果:

    00000000        00000100        00010000        00000000 
    
  4. [B]。在Big-Endian机器上:

    00000000        00010000        00000100        00000000
    

    我的问题是:

    如果我直接在Little Endian上应用左移 公约,应该给出:

    numb

    00000001 00000100 00000000 00000000
    

    numb << 10

    00010000 00000000 00000000 00000000
    

    但实际上,它给出了:

    00000000        00000100        00010000        00000000 
    

    为了达到第二个结果,我在上面展示了三个假设步骤。

    请解释为什么以上两个结果不同:numb << 10的实际结果与预期结果不同。

5 个答案:

答案 0 :(得分:177)

Endianness是值存储在内存中的方式。当加载到处理器中时,无论字节顺序如何,位移指令都在处理器寄存器中的值上运行。因此,从内存加载到处理器相当于转换为大端,接下来是移位操作,然后将新值存储回内存,这是小端字节顺序再次生效的地方。

更新,感谢@jww:在PowerPC上,向量移位和旋转是字节序敏感的。您可以在向量寄存器中使用值will produce different results on little-endian and big-endian

答案 1 :(得分:51)

不,像C的任何其他部分一样,bitshift是根据而不是表示来定义的。左移1是多重乘以2,右移是除法。 (与使用按位运算时一样,请注意有符号性。对于无符号整数类型,一切都是最明确定义的。)

答案 2 :(得分:4)

无论哪个移位指令移出,高阶位首先被认为是左移位。无论哪个移位指令首先移出低位,都被认为是右移位。从这个意义上说,>><<unsigned数字的行为不会取决于字节顺序。

答案 3 :(得分:3)

计算机不会像我们一样写下数字。价值只是转移。如果你坚持逐字节查看它(即使这不是计算机的工作方式),你可以说在小端机器上,第一个字节向左移,多余的位进入第二个字节,等等。

(顺便说一句,如果你把字节垂直而不是水平地写,那么little-endian更有意义,顶部有更高的地址。这通常是如何绘制存储器映射图。)

答案 4 :(得分:0)

尽管接受的答案指出,记忆力是记忆力的一个概念。但是我不认为直接回答这个问题。

一些答案​​告诉我按位运算不依赖于字节序,处理器可以用任何其他方式表示字节。无论如何,这是在说抽象性。

但是,例如当我们在纸上进行按位计算时,是否无需首先说明字节序?大多数情况下,我们会隐式选择一个字节序。

例如,假设我们有一行这样的代码

0x1F & 0xEF

您将如何在纸上手工计算结果?

  MSB   0001 1111  LSB
        1110 1111
result: 0000 1111

因此,这里我们使用Big Endian格式进行计算。您还可以使用Little Endian计算并获得相同的结果。

顺便说一句,当我们用代码写数字时,我认为这就像是Big Endian格式。 1234560x1F,最重要的数字从左开始。

同样,当我们在纸上写一个值的二进制格式后,我认为我们已经选择了Endianess,并且正在从内存中查看该值。

所以回到问题上,移位操作<<应该被认为是从LSB(最低有效字节)到MSB(最高有效字节)的转移。

然后以问题中的示例为例:

numb=1025

小尾数

LSB 00000001 00000100 00000000 00000000 MSB

因此<< 1010bit从LSB转换为MSB。


Little Endian格式的比较和<< 10操作:

MSB                                        LSB
    00000000  00000000  00000100  00000001  numb(1025)
    00000000  00010000  00000100  00000000  << 10

LSB                                        MSB
    00000000  00000100  00010000  00000000 numb(1025) << 10, and put in a Little Endian Format

LSB                                        MSB
    00000001  00000100  00000000  00000000 numb(1205) in Little Endian format
    00000010  00001000  00000000  00000000 << 1 
    00000100  00010000  00000000  00000000 << 2 
    00001000  00100000  00000000  00000000 << 3 
    00010000  01000000  00000000  00000000 << 4
    00100000  10000000  00000000  00000000 << 5
    01000000  00000000  00000001  00000000 << 6
    10000000  00000000  00000010  00000000 << 7
    00000000  00000001  00000100  00000000 << 8
    00000000  00000010  00001000  00000000 << 9
    00000000  00000100  00010000  00000000 << 10 (check this final result!)

哇!如操作说明所述,我得到了预期的结果!

OP未能获得预期结果的问题是:

  1. 似乎他没有从LSB转到MSB。

  2. 当以Little Endian格式转换位时,您应该意识到(感谢上帝,我意识到了):

LSB 10000000 00000000 MSB << 1
LSB 00000000 00000001 MSB LSB 01000000 00000000 MSB

由于每个8bits,我们实际上都是以MSB 00000000 LSB Big Endian格式编写的。

所以就像

LSB[ (MSB 10000000 LSB) (MSB 00000000 LSB) ]MSB


总结:

  1. 尽管据说按位运算已被抽象出来了……但是,当我们手动计算按位运算时,当我们在纸上写下二进制格式时,我们仍然需要知道我们正在使用什么字节序。另外,我们需要确保所有运算符都使用相同的字节序。

  2. OP未能获得预期的结果是因为他犯了错。