【问题标题】:confusion on little endian big endian对小端大端的困惑
【发布时间】:2013-10-24 21:09:52
【问题描述】:

我对小端/大端有些困惑。好像我不见了 某事简单。一些反馈表示赞赏。 例如,假设我们有两个函数分别检索
的最低和最高有效字节 32位值:

#define LSB(x) ((x) & 0x000000FF)

#define MSB(x) ((x) & 0xFF000000)

我的问题是:以上两个函数在 big endian 和 little endian 机器上是否返回正确的结果both

现在我将解释为什么我会感到困惑。 想象一下我们在一个小端机器上。在小端机器上,整数 9 存储在内存中,如下所示(十六进制): 09 00 00 00 (最低有效字节在前) 现在在某个时候,你可能会想,如果我们使用上面的 LSB 函数,那么我们将结束 加上这样的表达式: 09 00 00 00 & 00 00 00 FF 这是 0 - 但当然这不是上面的 LSB 函数最终会如何工作。所以看来我错过了。任何帮助表示赞赏。

另外,如果我说 int y = 0x000000FF - 无论机器的字节序如何,这都是 255,对吧?

【问题讨论】:

  • OT:不应该是#define MSB(x) (((x) & 0xFF000000) >> 24)还是#define MSB(x) ((x) >> 24)(假设传递了一个32位的值)?
  • 您可能需要MSB(x) = ((x) >> 24),否则if (MSB(x) == 0xFF) ... 之类的代码将不起作用。
  • 好的,我会研究一下,但目前我并不特别关心 LSB 和 MSB 函数的最佳实现

标签: c bitwise-operators


【解决方案1】:

不管字节顺序如何,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 最终都会加载完全相同的值。

【讨论】:

  • 请看我解释我为什么会感到困惑的段落,也许这会让你更清楚问题的哪一部分实际上我最困惑。 (例如,我说的地方 09 00 00 00 & 00 00 00 FF)
  • @dmcr_code,我已经解决了您的困惑。事实上,0x0000009memory 中存储为 09 00 00 00,但 ALU 仍将其视为 0x0000009。 ALU 没有字节序之类的东西,只有意义。当您将寄存器加载/存储到内存时,字节序会得到处理,但这只是存储问题,而不是处理问题。
  • 以 RAID 系统为例。数据存储在硬盘之间的片段中,但这只是存储的一个细节。因为底层系统负责存储和恢复数据,所以所有应用程序都会一致地看到数据。这与字节顺序相同。这是 CPU 期望数据如何在内存中布局的问题,但除了在内存中存储/恢复数据的过程之外,没有字节序这样的东西。
  • 好的,所以你的基本意思是,即使在小端系统 9 上存储在内存中是这样的:09 00 00 00,当我将它传递给实际的 LSB 宏时,它已经被解释为数字 0x000009 - 这就是你的意思吧?
  • @dmcr_code,完全正确。在处理过程中,存储无关紧要。因此,如果您的号码是0x00000009,即使内存将其存储为sigil of baphomet,它仍然是0x00000009,并且and0x000000FF 将给您9
【解决方案2】:

0x000000FF 始终为 255,与字节顺序无关。它在小端机器上存储FF 00 00 00,因此LSB(9) 将继续工作。

【讨论】:

    【解决方案3】:

    是的,无论字节顺序如何,它们都能正常工作。

    您用作掩码的数字和您作为输入提供的数字都具有相同的字节序,因此无论哪种方式,它们都会给出相同的结果。

    当您(例如)通过网络连接收到一个整数作为chars 的数组时,Endianess 就会成为一个问题。在这种情况下,您必须将这些 chars 以正确的顺序重新组合在一起以获得原始值。

    【讨论】:

      【解决方案4】:

      我的问题是:以上两个函数在大端和小端机器上都返回正确的结果吗?

      是的,他们有。当你想从一个不是你正在做的多字节数组中形成一个标量时,问题就来了。

      【讨论】:

        【解决方案5】:

        只要您将整数值视为单个实体而不是原始字节序列(在内存中、在网络上等),字节序问题就不会出现在您的代码中。

        因此,0x000000FF 始终为 255,而您的 LSBMSB 宏是正确的。

        【讨论】:

        • 看来我对其他事情感到困惑。那部分我在段落中解释了我谈论 09 00 00 00 & 00 00 00 FF .. 等。
        【解决方案6】:

        Endian 是关于如何使用内存的。在将字节序列化或反序列化到内存、存储或某种流时,您主要需要担心它。

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

        【讨论】:

        • 关于参数大小的好点,虽然问题是别的东西
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-08
        • 1970-01-01
        • 2012-10-17
        相关资源
        最近更新 更多