【问题标题】:Endianness macro in CC中的字节顺序宏
【发布时间】:2023-03-08 17:25:01
【问题描述】:

我最近看到post 是关于 C 中的字节顺序宏的,但我无法真正理解第一个答案。

支持任意字节顺序的代码,可以放入文件中 调用 order32.h:

#ifndef ORDER32_H
#define ORDER32_H

#include <limits.h>
#include <stdint.h>

#if CHAR_BIT != 8
#error "unsupported char size"
#endif

enum
{
    O32_LITTLE_ENDIAN = 0x03020100ul,
    O32_BIG_ENDIAN = 0x00010203ul,
    O32_PDP_ENDIAN = 0x01000302ul
};

static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
    { { 0, 1, 2, 3 } };

#define O32_HOST_ORDER (o32_host_order.value)

#endif

您可以通过以下方式检查小端系统

O32_HOST_ORDER == O32_LITTLE_ENDIAN

我确实理解一般的字节顺序。这就是我对代码的理解:

  1. 创建小端、中端和大端的示例。
  2. 将测试用例与小端、中端和大端的示例进行比较,并确定主机的类型。

我不明白的是以下几个方面:

  1. 为什么需要联合来存储测试用例uint32_t 不是保证能够根据需要保存 32 位/4 字节吗?分配{ { 0, 1, 2, 3 } } 是什么意思?它将值分配给联合,但为什么 strange 标记带有两个大括号?
  2. 为什么要检查CHAR_BIT?一条评论提到检查UINT8_MAX 会更有用吗?为什么char 甚至在这里使用,但不能保证它是 8 位宽?为什么不直接使用uint8_t?我找到了指向 Google-Devs github 的 this 链接。他们不依赖此检查...有人可以详细说明吗?

【问题讨论】:

    标签: c macros endianness


    【解决方案1】:

    为什么需要联合来存储测试用例?

        测试的重点是使用数组将创建的魔法值来为数组命名。

    uint32_t 不保证能够根据需要保存 32 位/4 字节吗?

       嗯,或多或少。它但是除了32位之外没有任何保证。它只会在一些你永远不会遇到的真正边缘架构上失败。

    分配{ { 0, 1, 2, 3 } } 是什么意思?它将值分配给联合,但为什么会有两个大括号的奇怪标记?

        内括号用于数组。

    为什么要检查CHAR_BIT?

        因为这是真正的保证。如果这不爆炸,一切都会好起来的。

    有一条评论提到检查UINT8_MAX? 会更有用,为什么这里甚至使用 char,但不能保证它是 8 位宽?

        因为事实上,现在总是如此。

    为什么不直接使用uint8_t? 我找到了这个指向 Google-Devs github 的链接。他们不依赖此检查...有人可以详细说明吗?

        许多其他选择也可以。

    【讨论】:

    • 谢谢!我想我明白了,当使用数组初始化程序初始化时,保证数据连续存储在内存中。当通过uint32_t 解决时,可以在之后测试字节序。实际上,当我尝试使用宏 032_HOST_ORDER 时,我确实遇到了错误。 error: invalid suffix '_HOST_ORDER' on integer constant.。你有什么想法吗,这里发生了什么?
    • 是的,第一个字母应该是 O oh 而不是零。
    【解决方案2】:

    初始化有两组大括号,因为内部大括号初始化bytes 数组。所以byte[0] 是 0,byte[1] 是 1,等等。

    联合允许uint32_tchar 数组位于相同的字节上,并以机器的字节序进行解释。所以如果机器是小端,0 在低位字节,3value 的高位字节。反之,如果机器是大端,0在高位字节,3value的低位字节。

    【讨论】:

    • 非常感谢!我现在明白了。但是,当我尝试访问 032_HOST_ORDER - error: invalid suffix '_HOST_ORDER' on integer constant 时,我确实遇到了错误。你知道这里发生了什么吗?
    • 错字:应该是O32_HOST_ORDER,而不是032_HOST_ORDER。标识符不能以数字开头。
    • 哦,我很愚蠢。非常感谢 - 你刚刚救了我。
    【解决方案3】:

    {{0, 1, 2, 3}} 是联合的初始化器,这将导致bytes 组件被[0, 1, 2, 3] 填充。

    现在,由于 bytes 数组和 uint32_t 占用相同的空间,您可以读取与原生 32 位整数相同的值。该整数的值向您展示了数组是如何被打乱的——这实际上意味着您使用的是哪个字节序系统。

    这里只有 3 种流行的可能性 - O32_LITTLE_ENDIANO32_BIG_ENDIANO32_PDP_ENDIAN

    至于char / uint8_t - 我不知道。我认为直接使用uint_8 而不进行检查更有意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-11
      • 1970-01-01
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      • 1970-01-01
      相关资源
      最近更新 更多