要强调的是:如果您在单个编译器/硬件平台上使用此软件结构,则字节顺序将不是问题。但是,如果您需要跨多个平台使用代码或数据,或需要匹配硬件位布局,则字节顺序就是一个问题。许多专业软件都是跨平台的,因此必须关注这一点。
以下是最简单的示例:我有一个将数字以二进制格式存储到磁盘中的代码。如果我没有显式地按字节写入和读取此数据,则从相反的字节顺序系统中读取的值将不同。
具体示例:
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。 过去,我们会将数据存储在磁盘上作为大端序,因为英特尔是异类,并提供了高速指令来交换字节。 如今,英特尔如此普遍,通常将小端序作为默认设置,并在大端序系统上进行交换。
一种较慢但字节序中立的方法是通过字节进行所有I/O,即:
uint_8 ubyte;
int_8 sbyte;
int16_t s;
fread((void*)&ubyte, 1, fp);
fread((void*)&sbyte, 1, fp);
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");
请注意,位域问题也存在,但与字节序问题无关。