【发布时间】:2026-02-02 20:45:01
【问题描述】:
我目前正在尝试创建一个 C 源代码,无论目标系统的字节序如何,它都能正确处理 I/O。
我选择了“小端”作为我的 I/O 约定,这意味着对于大端 CPU,我需要在写入或读取时转换数据。
转换不是问题。我面临的问题是检测字节序,最好在编译时检测(因为 CPU 在执行过程中不会改变字节序...)。
到目前为止,我一直在使用这个:
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
...
#else
...
#endif
它被记录为 GCC 预定义的宏,Visual 似乎也能理解它。
但是,我收到报告说某些 big_endian 系统 (PowerPC) 的检查失败。
因此,我正在寻找一种万无一失的解决方案,以确保正确检测到字节顺序,无论编译器和目标系统如何。好吧,至少他们中的大多数......
[Edit] : 大多数提出的解决方案都依赖于“运行时测试”。这些测试有时可能会在编译期间由编译器正确评估,因此不会消耗真正的运行时性能。
但是,使用某种 if (0) { ... } else { ... } >> 进行分支是不够的。在当前的代码实现中,变量和函数声明依赖于big_endian检测。这些不能用 if 语句改变。
嗯,很明显,有后备计划,就是重写代码……
我宁愿避免这种情况,但是,好吧,看起来希望越来越渺茫......
[编辑 2]:我通过深入修改代码测试了“运行时测试”。尽管他们正确地完成了工作,但这些测试也会影响性能。
我期待,由于测试具有可预测的输出,编译器可以消除不良分支。但不幸的是,它并不总是有效。 MSVC 是很好的编译器,并且可以成功地消除不良分支,但 GCC 的结果参差不齐,这取决于版本、测试类型,并且对 64 位的影响比对 32 位的影响更大。
这很奇怪。这也意味着运行时测试不能保证被编译器处理。
编辑 3 :这些天来,我正在使用编译时常量联合,期望编译器将其解决为明确的是/否信号。 而且效果很好: https://godbolt.org/g/DAafKo
【问题讨论】:
-
@BoPersson - 这不是编译时检测
-
运行时间是您最好的选择,但编译时间包含在以下答案中:1. *.com/a/1001373/1094175 2. *.com/a/2100385/1094175
-
一些 CPU 实际上可以对不同的可执行文件有不同的字节序。 en.wikipedia.org/wiki/Endianness#Bi-endian_hardware
-
@Cyan ,除了你提到的那些,没有一个。因此,要么编译一个检测字节序的小程序,并将结果输入你的构建系统,以便它定义一个预处理器宏,要么编写代码,使其独立于主机字节序。
-
基于预处理器的测试可能失败(误报)的原因是未定义的符号在
#if指令中被替换为0。
标签: c c-preprocessor endianness compile-time