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'步骤以更好地理解处理]
对待没有.在Big-Endian公约中:
00000000 00000000 00000100 00000001
Run Code Online (Sandbox Code Playgroud)应用左移:
00000000 00010000 00000100 00000000
Run Code Online (Sandbox Code Playgroud)再次在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上产生不同的结果.
Ker*_* SB 54
不,像C的任何其他部分一样,bitshift是根据值而不是表示来定义的.左移1是多重乘以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 来计算并得到相同的结果。
顺便说一句,当我们在代码中编写数字时,我认为这就像大端格式。123456
或0x1F
,最重要的数字从左侧开始。
再次强调,一旦我们在纸上写下某个值的二进制格式,我认为我们已经选择了 Endianess,并且我们正在查看该值,就像我们从内存中看到的那样。
回到问题,移位操作<<
应该被认为是从 LSB(最低有效字节)移位到 MSB(最高有效字节)。
那么就问题中的例子来说:
numb=1025
小尾数法
LSB 00000001 00000100 00000000 00000000 MSB
因此<< 10
将从10bit
LSB 转移到 MSB。
<< 10
Little 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没有得到预期结果的问题是:
看来他并没有从LSB转向MSB。
当以 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
总结:
虽然按位运算据说是抽象出来的 blablablabla...,但是当我们手工计算按位运算时,我们在纸上写下二进制格式时仍然需要知道我们使用的字节序。此外,我们需要确保所有运算符都使用相同的字节顺序。
OP没有得到预期的结果是因为他做错了换档。
无论哪个移位指令先移出高位,都被认为是左移。无论哪个移位指令先移出低位,都被认为是右移。在这个意义上说,行为>>
和<<
对unsigned
数将不依赖于字节序。
计算机不会像我们那样写下数字。价值只是发生了变化。如果您坚持逐字节查看(即使计算机不是这样做的),您可以说在小端机器上,第一个字节左移,多余的位进入第二个字节,等等。
(顺便说一句,如果您垂直而不是水平写入字节,并且较高的地址位于顶部,则小端序更有意义。这恰好是通常绘制内存映射图的方式。)