我对小端/大端有些困惑。似乎我失踪了
很简单。一些反馈意见。
例如,假设我们有两个函数可以检索
最小和最重要的字节
32位值:
#define LSB(x) ((x) & 0x000000FF)
#define MSB(x) ((x) & 0xFF000000)
我的问题是:上面两个函数是否在 big endian和 little endian机器上返回正确的结果 ?
现在我将解释为什么我有困惑。 想象一下,我们正在使用一台小型机器。在一个小端机器上,整数9存储在内存中,如下所示(十六进制):09 00 00 00(最低有效字节优先) 现在,在某些时候,您可能会认为,如果我们使用上面的LSB函数,那么我们就会结束 这样的表达:09 00 00 00& 00 00 00 FF为0 - 但当然不是LSB功能最终如何工作。所以我似乎错过了什么。任何帮助表示赞赏。
另外,如果我说int y = 0x000000FF
- 无论机器的endiannes是什么,这都是255?
答案 0 :(得分:11)
无论字节顺序如何,x & 0xFF
都会为您提供最不重要的字节。
首先,您应该了解字节序和重要性之间的区别。字节顺序表示将字节写入内存的顺序; 它与CPU中的任何计算完全无关。意义说明哪些位具有更高的值; 与任何存储系统完全无关。
将内存中的值加载到CPU后,它的字节顺序无关紧要,因为对于CPU(更准确地说,ALU)而言,重要的是位的重要性。
因此,就C而言,0x000000FF
在其最低有效字节中具有1,并且and
使用变量将赋予其最低有效字节。
事实上,在整个C标准中,你找不到“endian”这个词。 C定义了一个“抽象机器”,其中只有位的重要性才重要。编译器负责编译程序,使其行为与抽象机器相同,无论字节顺序如何。因此,除非您期望某种内存布局(例如通过union
或一组指针),否则您根本不需要考虑字节序。
您可能感兴趣的另一个例子是转移。同样的事情适用于转移。实际上,就像我之前所说的那样,字节序对ALU来说并不重要,所以<<
总是转换为甚至不是编译器转移到更重要的位,而是CPU本身,而不管字节顺序。
让我把它们放在一个有两个正交方向的图表中,这样你可能会更好地理解它。从CPU的角度来看,这就是加载操作的样子。
在小端机器上你有:
MEMORY CPU Register
LSB BYTE2 BYTE3 MSB ----> MSB
\ \ \-----------> BYTE3
\ \----------------> BYTE2
\--------------------> LSB
在大端机器上你有:
MEMORY CPU Register
/--------------------> MSB
/ /----------------> BYTE3
/ / /-----------> BYTE2
MSB BYTE3 BYTE2 LSB ----> LSB
如您所见,在这两种情况下,您都有:
CPU Register
MSB
BYTE3
BYTE2
LSB
这意味着在两种情况下,CPU最终加载完全相同的值。
答案 1 :(得分:3)
0x000000FF
始终为255。在小端机器上存储为FF 00 00 00
,因此LSB(9)
将继续有效。
答案 2 :(得分:1)
是的,无论是否有结果,这些都能正常工作。
您用作遮罩的数字和作为输入的数字都具有相同的字节顺序,因此它们会以相同的方式给出相同的结果。
当您拥有(例如)通过网络连接作为char
数组接收的整数时,Endianess成为一个问题。在这种情况下,您必须按正确的顺序将这些char
重新组合在一起以获得原始值。
答案 3 :(得分:1)
我的问题是:上面两个函数在big endian和little endian机器上都返回正确的结果吗?
是的,他们这样做。当您想要从多字节数组中形成标量时,问题就出现了。
答案 4 :(得分:0)
只要将整数值视为单个实体而不是原始字节序列(在内存中,在线上等),字节序的问题就不会出现在代码中。
因此,0x000000FF
始终为255,您的LSB
和MSB
宏也是正确的。
答案 5 :(得分:0)
Endian是关于如何使用内存的。在将字节序列化或反序列化为内存,存储或某种流时,您首先必须担心它。
我相信您的宏有时会工作,有时根据您的使用方式无法正常工作。如果x是一个int(假设你使用32位整数)那么你应该没问题,因为编译器知道int是什么以及当x不是32位数时它是如何表示的,你可能遇到问题。