Little-Endian

2017-10-10 Bin

在几乎所有的机器上,多字节对象都被存储为连续的字节序列。与之相应的就是连续字节的排序方式。

内存地址是线性增长的(从虚拟内存的角度看)。同样,连续字节的排布也是线性的。

所以就有了两种方案:字节的排布方向和内存的增长方向一致,或者相反。

具体内容可以查看Wiki

0x00 小端序

当内存的地址增长方向和字节的排布顺序一致时,称为小端序。

简单来说,就是”高高低低” – 字节的高位被放置在内存的高地址处,字节的低位被放置在内存的低地址处。

虽然道理很简单,但是在实际测试中事实和预期并不相同:

  • int型(4字节或8字节)的确按照小端序,比如0x11223344,0x11的地址比0x44高。
  • char类型只有一个字节(ASCII编码时),所以理所当然的就没有高低之分了。
  • string类型(char *char[])却表现相反,比如字符串”ABCD”,A的地址比D的地址低。

再考虑更实际的场景:如果使用结构体呢?如果我仅仅是malloc一段内存呢?

假设malloc了一个内存页大小的内存,里面的内容又是按什么顺序排列的呢?

答案很简单:未知

0x01 最小分割单位

回忆最开始提到的,大端序和小端序都是为了存储多字节对象设计的方案。

所以考虑字节序的时候,并不应该以内存片段为中心,而是应该是字节对象。

在C语言中,字节对象对应的就是各种变量类型:int, char, size_t, …

这些变量类型是字节序的最小分割单位。如果一个类型是几种类型复合而成,变量与变量之间的顺序由编译器决定(一般是按顺序排列,即第一个变量位于低地址处),变量自身的存储方式由字节序决定。

int和char都是最小的分割单位,所以在实际测试中,0x11223344中0x11的确位于高地址处。

char[]类型则是复合类型,本质上是由一堆char类型复合而成(字符数组),所以”ABCD”中字符A实际是数组中的第一个变量,根据编译器的决定,放置在低地址处。

更经典的例子是int[]类型。

假设一个int类型为4字节。如果有变量int foo[2],并且foo[0] = 0x11223344foo[1] = 0x55667788,那么在内存中变量foo的实际情况如下:

0   0x44
1   0x33
2   0x22
3   0x11
4   0x88
5   0x77
6   0x66
7   0x55

0x4433221188776655

至于malloc的内存,完全由写入方式决定。

结构体也是一样的道理。