操作系统:大小端问题

大小端问题的由来

为什么计算机世界需要区分大小端? 内存里存取的单位是字节, 如果所有的数据类型长度都是一个字节, 那就完全不需要大小端了, 每个变量都仅占据单独一个字节.

例如, 三个变量 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

大小端形式的优缺点

小端的优势:

  1. 以不同的长度读取变量非常方便, 不用计算地址. 例如u64 a=0x1234, 当(u16)a时, CPU不需要重新计算读取的起始位置, 永远都是变量a的起始地址.

  2. 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.”


创建于: 2022-11-17T10:30:35, Lastmod: 2023-09-24T18:08:59