大端和小端是指數據在內存中的存儲模式,它由 CPU 決定:
1) 大端模式(Big-endian)是指將數據的低位(比如 1234 中的 34 就是低位)放在內存的高地址上,而數據的高位(比如 1234 中的 12 就是高位)放在內存的低地址上。這種存儲模式有點兒類似於把數據當作字符串順序處理,地址由小到大增加,而數據從高位往低位存放。
2) 小端模式(Little-endian)是指將數據的低位放在內存的低地址上,而數據的高位放在內存的高地址上。這種存儲模式將地址的高低和數據的大小結合起來,高地址存放數值較大的部分,低地址存放數值較小的部分,這和我們的思維習慣是一致,比較容易理解。
為什么有大小端模式之分
計算機中的數據是以字節(Byte)為單位存儲的,每個字節都有不同的地址。現代 CPU 的位數(可以理解為一次能處理的數據的位數)都超過了 8 位(一個字節),PC機、服務器的 CPU 基本都是 64 位的,嵌入式系統或單片機系統仍然在使用 32 位和 16 位的 CPU。
對於一次能處理多個字節的CPU,必然存在着如何安排多個字節的問題,也就是大端和小端模式。以 int 類型的 0x12345678 為例,它占用 4 個字節,如果是小端模式(Little-endian),那么在內存中的分布情況為(假設從地址 0x 4000 開始存放):
內存地址 | 0x4000 | 0x4001 | 0x4002 | 0x4003 |
存放內容 | 0x78 | 0x56 | 0x34 | 0x12 |
如果是大端模式(Big-endian),那么分布情況正好相反:
內存地址 | 0x4000 | 0x4001 | 0x4002 | 0x4003 |
存放內容 | 0x12 | 0x34 | 0x56 | 0x78 |
我們的 PC 機上使用的是 X86 結構的 CPU,它是小端模式;51 單片機是大端模式;很多 ARM、DSP 也是小端模式(部分 ARM 處理器還可以由硬件來選擇是大端模式還是小端模式)。
借助共用體,我們可以檢測 CPU 是大端模式還是小端模式,請看代碼:
#include <stdio.h> int main(){ union{ int n; char ch; } data; data.n = 0x00000001; //也可以直接寫作 data.n = 1; if(data.ch == 1){ printf("Little-endian\n"); }else{ printf("Big-endian\n"); } return 0; }
在PC機上的運行結果:
Little-endian
共用體的各個成員是共用一段內存的。1 是數據的低位,如果 1 被存儲在 data 的低字節,就是小端模式,這個時候 data.ch 的值也是 1。如果 1 被存儲在 data 的高字節,就是大端模式,這個時候 data.ch 的值就是 0。