c - 与端序无关的转换为大端序的宏

标签 c endianness c11

是否可以在 C 中编写一个宏,它采用 uint32_t 并将其转换为大端表示,无论目标系统是小端还是大端,这样宏可以在编译时计算为常量吗?

我发现了这个问题:endianness conversion, regardless of endianness,但是,答案只提供功能。我的情况是我希望编译时表达式能够编写如下内容:

const uint32_t magic_number = BIGENDIAN32(0x12345678);

最佳答案

您可以使用依赖字节序的 union 以及不依赖字节序的移位。运行时版本:

uint32_t big_endian (uint32_t n)
{
  union
  {
    uint32_t u32;
    uint8_t  u8 [4];
  } be;

  for(size_t i=0; i<4; i++)
  {
    size_t shift = (4-1-i) * 8;
    be.u8[i] = (n >> shift) & 0xFFu;
  }
  return be.u32;
}

u8[0] 在大端机器上总是包含 MS 字节。但是,n >> shift 将可移植地抓取相关字节。值得注意的是,在大端机器上运行时,整个函数只是开销膨胀。

将其转换为丑陋的编译时宏将是这样的:

typedef union
{
  uint32_t u32;
  uint8_t  u8 [4];
} be_t;


#define BIG_ENDIAN(n) ( _Generic((n), uint32_t: (void)0), \
  (be_t){ .u8 = { ((n) >> 24)&0xFFu,                      \
                  ((n) >> 16)&0xFFu,                      \
                  ((n) >>  8)&0xFFu,                      \
                   (n)&0xFFu } }.u32)

_Generic check + , 运算符只是为了类型安全,如果卡在非标准 C 中,可以将其删除。该宏使用以下形式的临时 union 复合文字(外部 {}),初始化 u8 数组(内部 {}),然后返回一个 uint32_t 值。

在 little endian x86 上尝试 BIG_ENDIAN(0x12345678) 并反汇编,我得到:

mov     esi, 2018915346

2018915346 十二月 = 0x78563412

关于c - 与端序无关的转换为大端序的宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57975783/

相关文章:

c++ - 浮点字节顺序

c - 独立实现和托管实现之间是否存在有意义的区别?

c - 为什么 GCC 在设置为 O0 时仍然优化了一些东西?

c - atof 未在单链表中转换

linux - Endianness 是一种属性、硬件还是软件?

c - 为什么 C11 标准不会删除不安全的 strcat(),strcpy() 函数?

您可以使用指向包含结构的指针来修改嵌套结构的值吗?

c - 仅公开所需的信息,不包含不必要的头文件

c - 如何使用GDI将RGB位图绘制到窗口?

iPhone平台: endianness (detection & swapping)