位移是否依赖于端点?

假设我用数字 'numb'=1025 [00000000 00000000 00000100 00000001]表示:

关于 Little-Endian 机器:

00000001 00000100 00000000 00000000

关于 Big-Endian 机器:

00000000 00000000 00000100 00000001

现在,如果我在10位上应用 Left Shift (比如: 数字麻木 < = 10) ,我应该:

关于 Little-Endian 机器:

正如我在 GDB 中注意到的那样,Little Endian 用3个步骤完成了 Left Shift: [我已经展示了‘3’个步骤来更好地理解处理过程]

  1. 对待大-恩迪安公约中的否定:

    00000000        00000000        00000100    00000001
    
  2. Apply Left-Shift:

    00000000        00010000        00000100        00000000
    
  3. Represent the Result again in Little-Endian:

    00000000        00000100        00010000        00000000
    

[B]. On Big-Endian Machine:

00000000        00010000        00000100        00000000

我的问题是:

如果我直接在小 Endian 上应用一个左移 公约应该给予:

返回文章页面

00000001 00000100 00000000 00000000

返回文章页面

00010000 00000000 00000000 00000000

但实际上,它给出了:

00000000        00000100        00010000        00000000

为了得到第二个结果,我已经展示了上面的三个假设步骤。

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

43904 次浏览

不,位移和 C 的其他部分一样,是根据 价值观而不是表示来定义的。左移1是乘以2,右移是除法。(与使用位操作时一样,要注意符号性。对于无符号整数类型,一切都是最好定义的。)

计算机不像我们这样记数字。价值只是转移。如果你坚持一个字节一个字节地看(即使计算机不是这样做的) ,你可以说在一个小端机器上,第一个字节左移,多余的比特进入第二个字节,等等。

(顺便说一下,如果您垂直而不是水平地写入字节,并且顶部有更高的地址,little-endian 会更有意义。这正是内存映射图通常的绘制方式。)

Endianness 是将值存储在内存中的方式。当加载到处理器中时,不管 endianness 是什么,位移指令都是对处理器寄存器中的值进行操作的。因此,从存储器加载到处理器相当于转换到大端,移位操作接下来进行,然后新的值被存储回存储器,这是小端字节顺序再次生效的地方。

更新,感谢@jww: 在 PowerPC 上,矢量位移和旋转是端点敏感的。您可以在向量寄存器中有一个值和一个偏移 对小端点和大端点会产生不同的结果

无论移位指令首先移出高阶位,都被认为是左移位。无论哪个移位指令首先移出低阶位被认为是正确的移位。在这个意义上,>><<对于 unsigned数的行为将不依赖于 endianness。

虽然公认的答案指出,恩迪尼斯是一个概念,从记忆的观点。但我不认为这能直接回答问题。

有些答案告诉我,按位运算不依赖于字节顺序和处理器可能以任何其他方式表示字节。不管怎么说,这是一个抽象的概念。

但是,当我们在纸上做一些按位计算时,例如,不需要首先声明最终结果吗?大多数情况下,我们会含蓄地选择一个优势。

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

0x1F & 0xEF

你如何用手算出结果,在纸上?

  MSB   0001 1111  LSB
1110 1111
result: 0000 1111

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

顺便说一句,当我们用代码写数字的时候,我觉得它就像是大恩迪安格式。1234560x1F,最重要的数字从左边开始。

同样,只要我们在纸上写一些二进制格式的值,我想我们已经选择了 Endianess,我们正在查看从内存中看到的值。

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

那么问题中的例子是:

numb=1025

小 Endian

LSB 00000001 00000100 00000000 00000000 MSB

所以 << 10将是 10bit从 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 所描述的预期结果!

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. 虽然按位运算被认为是抽象的,但是当我们手工计算按位运算时,我们仍然需要知道我们在纸上写下二进制格式时使用的是什么字节。此外,我们还需要确保所有运算符使用相同的 endianess。

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