【问题标题】:Define macros based on endianness of machine根据机器的字节序定义宏
【发布时间】:2019-09-02 04:58:47
【问题描述】:

我想根据机器的字节序在结构中定义变量,这是我尝试过的

#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)
//#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})
struct A {
    #if IS_BIG_ENDIAN
    char a:4;
    char b:4;
    #else
    char b:4;
    char a:4;
    #endif
}

以上代码报错,是否可以实现。我的主要目标是实现结构变量的逆序。

【问题讨论】:

  • 另外,请注意位域的布局是实现定义的[class.bit]/1。所以请注意,这本质上不是一种可移植的做事方式……
  • Byte order fallacy tldr;机器的字节顺序无关紧要重要的是数据的字节顺序
  • 通过联合的类型双关语通常是 UB,我不知道 charchar[] 有一个例外(与指针一样,所有这些都可以合法地转换为 char* ...)
  • 你为什么要那个?您想通过按原样打印结构的字节来进行序列化吗?这在其他方面也很危险——例如。 G。对齐:struct S { int32_t i32; int64_t i64; }; 在 32 位编译器上的大小可能为 12,但在 64 位编译器上为 16,因为两个成员之间存在字节填充!

标签: c++ c++11 endianness


【解决方案1】:

来自https://sourceforge.net/p/predef/wiki/Endianness/

你没有标准的方式来拥有它。

但自定义标头 <sys/param.h><endian.h> 可能会提供 MACRO,例如:

Type                            Macro           Value
Big endian                      __BYTE_ORDER    __BIG_ENDIAN
Little endian                   __BYTE_ORDER    __LITTLE_ENDIAN
Little endian (word-swapped)    __BYTE_ORDER    __PDP_ENDIAN

【讨论】:

    【解决方案2】:

    等到 C++20(或使用编译器的实验性功能),您将能够为此使用 C++ 标准 std::endian

    表示所有标量类型的字节序:

    如果所有标量类型都是小端,std::endian::native 等于 std::endian::little 如果所有标量类型都是大端, std::endian::native 等于 std::endian::big

    【讨论】:

      【解决方案3】:

      该测试不适用于预处理器 if 指令。

      即将推出的 C++20 建议使用std::endian。它可以在没有预处理器的情况下使用。

      static_assert(std::endian::native == std::endian::big
                 || std::endian::native == std::endian::little);
      
      struct ABig {
          char a:4;
          char b:4;
      };
      
      struct ALit {
          char b:4;
          char a:4;
      };
      
      using A = std::conditional_t<std::endian::native == std::endian::big, ABig, ALit>;
      

      在 C++20 之前,没有获得字节顺序的标准方法。

      一种可移植的解决方案是使用预定义的宏来检测系统。一些系统是小端(Windows),而另一些系统则提供带有宏定义的标头(Linux 中的&lt;endian.h&gt;,BSD 中的&lt;sys/endian.h&gt; 等等),而其他系统可能在其他方面有所不同。 GCC 编译器提供宏:

      __BYTE_ORDER__
      __ORDER_LITTLE_ENDIAN__
      __ORDER_BIG_ENDIAN__
      __ORDER_PDP_ENDIAN__
      

      也就是说,几乎位字段表示的每个方面都是由实现定义的,如果准确的顺序很重要——看起来确实如此——那么你将不得不依赖特定的实现无论如何,因此无法实现便携性。确定您的目标系统,一旦确定,请查阅该系统的文档以了解如何获得字节序。

      最好不要依赖位域的表示。

      【讨论】:

        【解决方案4】:

        感谢@Jarod42,以下代码对我有用

        #define IS_BIG_ENDIAN (__BYTE_ORDER__ == __BIG_ENDIAN)
        struct A {
            #if IS_BIG_ENDIAN
            char a:4;
            char b:4;
            #else
            char b:4;
            char a:4;
            #endif
        };
        

        【讨论】:

          猜你喜欢
          • 2018-07-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-23
          • 2016-11-29
          • 1970-01-01
          相关资源
          最近更新 更多