用十进制数来类比可能是最容易的:
取数字 308。它有三个数字,“3”、“0”和“8”。按照惯例,左边的数字比右边的数字更重要。但约定也可以很容易地采用另一种方式……数字可以以相反的顺序书写(例如,803)。
为什么这是相关的?考虑计算机上数字的十六进制表示:0xabcd0123。在严格的数学意义上,可以将此数字视为 4 基数 256 位。 (即,0xab、0xcd、0x01、0x23)。因此,字节序是关于这些 radix-256 数字在写入内存时的排序约定。
Little-endian 表示“将最低有效位写入最低地址”;
Big-endian 的意思是“将最高有效位写入最低地址”。
所以,关于处理字节序的机制:
如果您考虑上面的十进制示例,您将如何获得每个数字?通过取模 10 的数字给出最低有效位(即 308 % 10 = 8)。第二个数字可以通过将数字除以 10,然后取模 10(即 308 / 10 = 30; 30 % 10 = 0)等等。
对于计算机上的二进制数据,该过程完全相同,只是它被视为 radix-256 而不是像十进制数字那样的 radix-10。这就是一些技巧的用武之地。
- 使用 2 的幂的模数进行模运算时,可以通过 AND 进行。让 m=256 作为我们的模数。因为 m = 2 的某个幂,所以 x % m 等价于 x & (m-1)。这是一个超出此答案范围的数字事实。
- 在进行 2 的幂除法时,可以通过右移进行。也就是说,让 m=256 成为我们的除数。因为 m = 2 的 8 次方,所以 x / m 等价于 x >> 8。
因此,特定于二进制字节序的序列化完全使用上述过程:
uint32_t val = 0xabcd0123;
(val & 0xff) 等价于 (val % 256),并产生 0x23。
((val >> 8) & 0xff) 等价于 ((val / 256) % 256),并产生 0x01。
((val >> 16) & 0xff) 等价于 (((val / 256)/256) % 256),并产生 0xcd。
等等。因此,现在您可以访问数字/字节,您只需选择存储它们的顺序。如上所述,“大端 = 最低地址最重要”,“小端 = 最低地址最不重要”。