位移是否取决于字节序?

San*_*ngh 146 c endianness

假设我有'numb'=1025 [00000000 00000000 00000100 00000001]代表的数字:

在Little-Endian机器上:

00000001 00000100 00000000 00000000
Run Code Online (Sandbox Code Playgroud)

在Big-Endian机器上:

00000000 00000000 00000100 00000001
Run Code Online (Sandbox Code Playgroud)

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

[A]在Little-Endian机器上:

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

  1. 对待没有.在Big-Endian公约中:

    00000000        00000000        00000100    00000001
    
    Run Code Online (Sandbox Code Playgroud)
  2. 应用左移:

    00000000        00010000        00000100        00000000
    
    Run Code Online (Sandbox Code Playgroud)
  3. 再次在Little-Endian中表示结果:

    00000000        00000100        00010000        00000000 
    
    Run Code Online (Sandbox Code Playgroud)

[B].在Big-Endian机器上:

00000000        00010000        00000100        00000000
Run Code Online (Sandbox Code Playgroud)

我的问题是:

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

numb:

00000001 00000100 00000000 00000000
Run Code Online (Sandbox Code Playgroud)

numb << 10:

00010000 00000000 00000000 00000000
Run Code Online (Sandbox Code Playgroud)

但实际上,它给出了:

00000000        00000100        00010000        00000000 
Run Code Online (Sandbox Code Playgroud)

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

请解释一下为什么上述两个结果不同:实际结果numb << 10与预期结果不同.

Car*_*arl 187

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

更新,感谢@jww:在PowerPC上,向量移位和旋转是字节序敏感的.你可以在向量寄存器中有一个值,并且shift 会在little-endian和big-endian上产生不同的结果.

  • 理解字节序的最好方法是在嵌入级别的不同体系结构上真正使用它.但是,我可以向您推荐这两篇文章:http://www.codeproject.com/KB/cpp/endianness.aspx和http://www.ibm.com/developerworks/aix/library/au-endianc/index html的?CA = DRS- (4认同)
  • 感谢您的解释.能否请一些参考资料,我可以更好地了解这些错综复杂的内容. (3认同)
  • 所以我的代码无论endian都能正常工作?!这很棒!我一直很担心我不得不将我的代码破解成地狱和背部! (3认同)
  • 在PowerPC上,向量的移位和旋转对字节序敏感。您可以在向量寄存器中有一个值,而移位将在小端和大端上产生不同的结果。 (3认同)
  • @MarcusJ:不一定.例如,如果您从表示32位整数的文件中读取4个字节,则需要考虑所读数据的字节顺序以及接收数据的系统的字节顺序,以便正确解释数据. (2认同)
  • 刚刚确认了这一点.我想知道为什么内存中的16位小端数字1(0b0000000100000000)在向右移位时保持为(0b0000000000000000).事实证明,寄存器中没有字节概念.它只是16位的直接数据.这意味着我的号码被加载为(0b0000000000000001),然后被移出寄存器. (2认同)
  • @jww 但是矢量移位不是一种只能通过库或程序集访问的特殊事物吗?这不适用于普通的 C `&gt;&gt;` 或 `&lt;&lt;` 运算符,对吗? (2认同)

Ker*_* SB 54

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

  • @Edmund:嗯...最值得注意的是没有指定签名的实现,因此按位运算(如右移)和模和除的行为是在负整数上定义的实现.你有什么其他的东西是实现定义的? (2认同)

Ric*_*ick 12

尽管公认的答案指出,字节顺序是从内存角度来看的一个概念。但我认为这并不能直接回答问题。

一些答案告诉我,按位运算不依赖于字节顺序,并且处理器可以以任何其他方式表示字节。不管怎样,它谈论的是字节顺序被抽象。

但是,例如,当我们在纸上进行一些按位计算时,不需要首先说明字节顺序吗?大多数时候我们隐式地选择字节序。

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

0x1F & 0xEF

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

  MSB   0001 1111  LSB
        1110 1111
result: 0000 1111
Run Code Online (Sandbox Code Playgroud)

所以这里我们使用Big Endian格式来进行计算。您也可以使用Little Endian 来计算并得到相同的结果。

顺便说一句,当我们在代码中编写数字时,我认为这就像大端格式。1234560x1F,最重要的数字从左侧开始。

再次强调,一旦我们在纸上写下某个值的二进制格式,我认为我们已经选择了 Endianess,并且我们正在查看该值,就像我们从内存中看到的那样。

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

那么就问题中的例子来说:

numb=1025

小尾数法

LSB 00000001 00000100 00000000 00000000 MSB

因此<< 10将从10bitLSB 转移到 MSB。


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

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!)
Run Code Online (Sandbox Code Playgroud)

哇!我得到了OP所描述的预期结果!

OP没有得到预期结果的问题是:

  1. 看来他并没有从LSB转向MSB。

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

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

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

所以就像

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


总结:

  1. 虽然按位运算据说是抽象出来的 blablablabla...,但是当我们手工计算按位运算时,我们在纸上写下二进制格式时仍然需要知道我们使用的字节序。此外,我们需要确保所有运算符都使用相同的字节顺序。

  2. OP没有得到预期的结果是因为他做错了换档。


Dav*_*lor 6

无论哪个移位指令先移出高位,都被认为是左移。无论哪个移位指令先移出低位,都被认为是右移。在这个意义上说,行为>><<unsigned数将不依赖于字节序。

  • 这种具体的解释方式正是我需要阅读的 - 谢谢! (2认同)

Ray*_*hen 5

计算机不会像我们那样写下数字。价值只是发生了变化。如果您坚持逐字节查看(即使计算机不是这样做的),您可以说在小端机器上,第一个字节左移,多余的位进入第二个字节,等等。

(顺便说一句,如果您垂直而不是水平写入字节,并且较高的地址位于顶部,则小端序更有意义。这恰好是通常绘制内存映射图的方式。)