小端大端的混淆

时间:2013-10-16 16:27:55

标签: c bitwise-operators

我对小端/大端有些困惑。似乎我失踪了 很简单。一些反馈意见。 例如,假设我们有两个函数可以检索
最小和最重要的字节 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?

6 个答案:

答案 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,您的LSBMSB宏也是正确的。

答案 5 :(得分:0)

Endian是关于如何使用内存的。在将字节序列化或反序列化为内存,存储或某种流时,您首先必须担心它。

我相信您的宏有时会工作,有时根据您的使用方式无法正常工作。如果x是一个int(假设你使用32位整数)那么你应该没问题,因为编译器知道int是什么以及当x不是32位数时它是如何表示的,你可能遇到问题。