C++字节序(大端和小端)以及判别方法(新手必看)
字节序(endianness)是计算机系统中数据表示的一种方式,定义了多字节数据在内存中的存储顺序。
字节序主要有两种类型:大端字节序(big-endian)和小端字节序(little-endian),理解这两种字节序对于在不同系统之间进行数据交换和存储非常重要。
例如,假设有一个 32 位整数 0x12345678,它按大端字节序存储在内存中的方式如下:
例如,同样的 32 位整数 0x12345678 按小端字节序存储在内存中的方式如下:
例如,大端字节序:
通过以上代码,我们可以确定当前系统使用的是大端字节序还是小端字节序。
另外,C++ 20 引入了枚举类 std::endian,用于指示标量类型的字节序。这个枚举类定义在头文件 <bit>中,并包含 3 个可能的值:little、big 和 native。这里的 native 表示当前平台使用的字节序:
这个特性的实现可能根据不同的编译器和平台而有所不同。下面是基于 std::endian 的改写版本:
字节序主要有两种类型:大端字节序(big-endian)和小端字节序(little-endian),理解这两种字节序对于在不同系统之间进行数据交换和存储非常重要。
大端字节序
在大端字节序中,数据的最高有效字节(most significant byte,MSB)存储在内存的最低地址处,而最低有效字节(least significant byte,LSB)存储在内存的最高地址处。这种排列方式类似于我们书写数字的方式,从左到右依次递减。例如,假设有一个 32 位整数 0x12345678,它按大端字节序存储在内存中的方式如下:
地址 内容 0x00 0x12 0x01 0x34 0x02 0x56 0x03 0x78
小端字节序
在小端字节序中,数据的最低有效字节存储在内存的最低地址处,而最高有效字节存储在内存的最高地址处。这种排列方式与大端字节序相反,从左到右依次递增。例如,同样的 32 位整数 0x12345678 按小端字节序存储在内存中的方式如下:
地址 内容 0x00 0x78 0x01 0x56 0x02 0x34 0x03 0x12
大端字节序与小端字节序的区别
大端字节序和小端字节序的主要区别在于数据在内存中的排列顺序。大端字节序强调数据的“重要性”,将最高有效字节放在首位;而小端字节序强调数据的“顺序性”,将最低有效字节放在首位。例如,大端字节序:
0x12345678 (MSB -> LSB) 地址: 0x00 0x01 0x02 0x03 数据: 0x12 0x34 0x56 0x78小端字节序:
0x12345678 (LSB -> MSB) 地址: 0x00 0x01 0x02 0x03 数据: 0x78 0x56 0x34 0x12
检查当前系统的字节序
首先,可以通过编写简单的 C++ 代码来检查当前系统的字节序:#include <iostream> void check_endianness() { unsigned int num = 1; if (*(char *)&num == 1) { std::cout << "系统是小端字节序 (Little Endian)" << std::endl; } else { std::cout << "系统是大端字节序 (Big Endian)" << std::endl; } } int main() { check_endianness(); return 0; }运行结果为(不唯一):
系统是小端字节序 (Little Endian)
通过以上代码,我们可以确定当前系统使用的是大端字节序还是小端字节序。
另外,C++ 20 引入了枚举类 std::endian,用于指示标量类型的字节序。这个枚举类定义在头文件 <bit>中,并包含 3 个可能的值:little、big 和 native。这里的 native 表示当前平台使用的字节序:
- 如果所有标量类型都是小端字节序,那么 std::endian::native 将等于 std::endian::little。
- 如果所有标量类型都是大端字节序(big-endian),那么 std::endian::native 将等于 std::endian::big。
- 在一些特殊情况下,比如所有标量类型的大小(sizeof)都等于 1,那么字节序就不重要,std::endian::little、std::endian::big 和 std::endian::native 将会有相同的值。
- 如果平台使用混合字节序(mixed-endian),则 std::endian::native 不会等于 std::endian::big,也不会等于 std::endian::little。
这个特性的实现可能根据不同的编译器和平台而有所不同。下面是基于 std::endian 的改写版本:
#include <bit> // 包含 std::endian #include <iostream> void check_endianness() { if constexpr (std::endian::native == std::endian::little) { std::cout << "系统是小端字节序 (Little Endian)" << std::endl; } else if constexpr (std::endian::native == std::endian::big) { std::cout << "系统是大端字节序 (Big Endian)" << std::endl; } else { std::cout << "系统是混合字节序 (Mixed Endian)" << std::endl; } } int main() { check_endianness(); return 0; }这种方法更为直接且具有类型安全,依赖于编译时的 if constexpr 语句来确定字节序,因此不会有运行时的性能开销。此外,它也避免了对指针的操作,更符合现代 C++ 的安全和抽象的原则。
字节序的应用场景
字节序在以下几种情况下尤为重要:- 跨平台数据交换:不同平台可能采用不同的字节序,因此在进行跨平台数据交换时需要考虑字节序转换,以确保数据在不同系统之间正确解析。
- 文件存储:某些文件格式会明确规定采用哪种字节序存储数据,解析这些文件时需要遵循相应的字节序规则。
- 网络传输:网络协议通常采用大端字节序(网络字节序),在发送和接收数据时需要进行相应的字节序转换。