最突出的一点是:如果您在单个编译器/硬件平台上使用它作为仅软件结构,那么字节序将不是问题。如果您在多个平台上使用代码或数据,或者需要匹配硬件位布局,那么这是一个问题。而且很多专业软件都是跨平台的,所以需要注意。
这是最简单的例子:我有以二进制格式将数字存储到磁盘的代码。如果我自己不明确地逐字节地写入和读取这些数据到磁盘,那么如果从相反的字节序系统读取,它将不会是相同的值。
具体例子:
int16_t s = 4096; // a signed 16-bit number...
假设我的程序在磁盘上附带了一些我想读入的数据。假设在这种情况下我想将其加载为 4096 ......
fread((void*)&s, 2, fp); // reading it from disk as binary...
在这里,我将其读取为 16 位值,而不是显式字节。这意味着如果我的系统与存储在磁盘上的字节序匹配,我得到 4096,如果不匹配,我得到 16 !!!!!!
所以字节序最常见的用法是批量加载二进制数,如果不匹配则进行 bswap。过去,我们将数据以大端序存储在磁盘上,因为英特尔是个奇怪的人,并提供高速指令来交换字节。如今,英特尔如此普遍,以至于经常将 Little Endian 设为默认值,并在大端系统上进行交换。
一种较慢但字节序中性的方法是按字节执行所有 I/O,即:
uint_8 ubyte;
int_8 sbyte;
int16_t s; // read s in endian neutral way
// Let's choose little endian as our chosen byte order:
fread((void*)&ubyte, 1, fp); // Only read 1 byte at a time
fread((void*)&sbyte, 1, fp); // Only read 1 byte at a time
// Reconstruct s
s = ubyte | (sByte << 8);
请注意,这与您为进行字节序交换而编写的代码相同,但您不再需要检查字节序。您可以使用宏来减轻这种痛苦。
我使用了程序使用的存储数据的示例。提到的另一个主要应用是编写硬件寄存器,这些寄存器具有绝对顺序。一个非常常见的地方是图形。弄错字节顺序,你的红色和蓝色通道就会反转!同样,问题在于可移植性——您可以简单地适应给定的硬件平台和显卡,但如果您希望相同的代码在不同的机器上工作,则必须进行测试。
这是一个经典的测试:
typedef union { uint_16 s; uint_8 b[2]; } EndianTest_t;
EndianTest_t test = 4096;
if (test.b[0] == 12) printf("Big Endian Detected!\n");
请注意,位域问题也存在,但与字节顺序问题正交。