大小端问题的由来
为什么计算机世界需要区分大小端? 内存里存取的单位是字节, 如果所有的数据类型长度都是一个字节, 那就完全不需要大小端了, 每个变量都仅占据单独一个字节.
例如, 三个变量 a=10, b=20, c=30
, 在内存中的布局可能就是:
┌────────────┐
│ │
│ 10 │ a
├────────────┤
│ │
│ 20 │ b
├────────────┤
│ │
│ 30 │ c
├────────────┤
│ │
│ │
│ │
│ │
│ │
└────────────┘
但是我们最常使用的数据类型肯定有超过一个字节的, int
类型在64位的系统中就占4个字节. 例如变量a=0xaabbccdd
一个变量的大小一旦超过4个字节, 内存的存取又是以字节位单位的, 那么要把它塞到内存里就必然会产生两种不同存放方式: 先放0xaa
还是先放0xdd
首先, 0xdd
是变量a的低8位, 0xaa
是最高8位, 这是确定的.
如果先放
0xaa
, 即低地址放高位, 就叫做大端, 如左图;如果先放
0xdd
, 即低地址放低位, 就叫小端, 如右图.
start addr of `a` start addr of `a`
┌────────────┐ ┌────────────┐
│ │ │ │
│ aa │ │ dd │
├────────────┤ ├────────────┤
│ │ │ │
│ bb │ │ cc │
├────────────┤ ├────────────┤
│ │ │ │
│ cc │ │ bb │
├────────────┤ ├────────────┤
│ │ │ │
│ dd │ │ aa │
├────────────┤ ├────────────┤
│ │ │ │
│ │ │ │
└────────────┘ └────────────┘
什么情况?
看下面的代码, 猜测输出的结果
unsigned int i = 0x00646c72;
printf("Hello Wo%s", &i);
%s
会按字节一直打印内存中的字符, 直到遇到\0
. 首先打印的字符便是变量i
的地址处的内容.
如果是小端存储方式, 变量i
的地址处的一个字节值是0x72, 即字符r
. 以此类推, 所以如果CPU的字节序是小端形式, 那么printf
的结果是: Hello world
大小端形式的优缺点
小端的优势:
以不同的长度读取变量非常方便, 不用计算地址. 例如
u64 a=0x1234
, 当(u16)a
时, CPU不需要重新计算读取的起始位置, 永远都是变量a的起始地址.Easily to do mathematical computations “because of the 1:1 relationship between address offset and byte number (offset 0 is byte 0), multiple precision math routines are correspondingly easy to write.”