union是用户定义类型,所有成员共享同一内存位置,大小等于最大成员,任一时刻仅一个成员有效,用于节省内存或类型转换。

用 union 一次性读取多字节整数的最低字节
最直观的方式是让编译器把同一个内存位置同时解释为整数和字节数组。定义一个 union,包含 uint32_t 和 uint8_t[4],写入 0x01020304 后看 bytes[0] 是 0x01 还是 0x04:
union { uint32_t i; uint8_t bytes[4]; } u;
u.i = 0x01020304;
bool is_little_endian = (u.bytes[0] == 0x04);
这个方法不依赖平台 ABI 或对齐假设,union 成员共享起始地址是 C++ 标准保证的(C++11 起)。但要注意:不能在 constexpr 上下文中使用(因为涉及运行时写入),且某些严格别名检查开启时(如 -fstrict-aliasing)可能被误判——不过对 union 成员的访问是标准特例,实际编译器均支持。
用指针强制 reinterpret_cast 判定更轻量
如果只想快速判断、不关心可读性,直接取 int 地址并转成 uint8_t* 更省事:
int test = 1; bool is_little_endian = (*reinterpret_cast<uint8_t>(&test) == 1);</uint8_t>
原理一样:整数 1 在内存中只占最低字节为 0x01,其余为 0x00。小端机上 &test 指向的就是那个 0x01;大端机上则指向高位的 0x00。
- 比
union少一次变量定义,适合宏或内联函数封装 - 注意:
int长度不固定(可能是 2/4/8 字节),用int32_t更稳妥 - 不能用于
constexpr函数(reinterpret_cast不允许)
编译期检测:用 std::endian(C++20)
C++20 引入了标准常量,可在编译期直接判断:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
#include <type_traits>
#if __cpp_lib_endian >= 201907L
constexpr bool is_little_endian = (std::endian::native == std::endian::little);
#endif</type_traits>
这是唯一真正零开销、可 constexpr、跨平台安全的方式。但需确认工具链支持:
- GCC 10+、Clang 11+、MSVC 19.28+ 支持
- 旧版本编译会跳过该分支,必须搭配运行时 fallback
-
std::endian::native是编译目标平台的端序,不是运行时 CPU 切换后的动态值(不存在“运行时切换端序”这回事)
常见误判点:网络字节序 ≠ 本地字节序,别混淆 ntohl
有人试图用 ntohl(0x01020304) 返回值反推本地端序,这是错的:
-
ntohl总是把网络序(大端)转成本地序,它本身不暴露本地序——你看到的返回值只是转换结果,无法逆向得出“为什么是这个结果” - 不同平台调用
ntohl可能生成相同数值(比如输入0x01020304在大小端机上都返回某个固定值),无法区分 -
ntohl是运行时函数,有调用开销,且依赖<arpa></arpa>(非 Windows 原生)
真正需要端序转换时,应直接用 htons/ntohl 等函数;仅做检测时,绕开它们更干净。
最容易被忽略的是:端序只对多字节标量类型有意义,char 和 bool 没有端序问题;另外,某些嵌入式平台(如部分 ARM)支持运行时端序切换,但普通 x86/x64/AArch64 固定为小端,检测结果恒定。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










