根据计算机的字节序定义宏

Define macros based on endianness of machine

本文关键字:定义 字节 计算机      更新时间:2023-10-16

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

#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
}

上面的代码给出了错误,这是可以实现的吗?我的主要目标是实现结构变量的相反顺序。

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

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

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

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

该测试不适用于预处理器 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中的<endian.h>,BSD中的<sys/endian.h>等),而其他系统可能在其他方面有所不同。GCC 编译器提供宏:

__BYTE_ORDER__
__ORDER_LITTLE_ENDIAN__
__ORDER_BIG_ENDIAN__
__ORDER_PDP_ENDIAN__

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

最好不要依赖位字段的表示形式。

等到 C++20(或使用编译器的实验功能),您将能够使用C++标准 std::endian 来实现这一点:

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

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

谢谢@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
};