在看深入理解計算機這本神書時看到一個地方挺有意思的。
一個多字節對象在內存中的排列順序是什麼樣子的?在幾乎所有的機器上多字節對象被存儲爲連續的字節序列,對象使用的地址爲所用字節中的最小地址。例如假設一個32位系統下的int變量x的地址爲0x100即&x的值爲0x100,那麼x的四個字節將會被存儲在存儲器的0x100、0x101、0x102、0x103位置。
它們的排列順序主要有兩種
小端法(little-endian)
最低有效字節排列在最前面的方式叫做小端法。比如32位int值爲0x0123456,起始地址爲0x100,那麼在應用小端法的機器中,表示爲
地址 | 0x100 | 0x101 | 0x102 | 0x103 |
---|---|---|---|---|
值 | 67 | 45 | 23 | 01 |
大端法(big-endian)
與小端法相對應,將最高有效字節排列在最前面的方式叫做大端法。還是一樣的例子,32位int值爲0x0123456,起始地址爲0x100,那麼在應用大端法的機器中,表示爲
地址 | 0x100 | 0x101 | 0x102 | 0x103 |
---|---|---|---|---|
值 | 01 | 23 | 45 | 67 |
還用許多比較新的機器採用雙端法(bi-endian),就是可以配置成大端或小端的機器來運行
總結與應用場景
沒有技術上的原因選擇哪個字節順序排列,只要一直堅持一種就好了
下面是按字節輸出內存中的值代碼
#include
typedef unsigned char * byte_pointer;
void show_bytes(byte_pointer start,int len)
{
int i;
for (i = 0; i < len; i++)
{
printf("%.2x ", start[i]);
}
printf("\n");
}
void show_int(int x)
{
show_bytes((byte_pointer)&x,sizeof(x));
}
void show_float(float x)
{
show_bytes((byte_pointer)&x, sizeof(x));
}
void show_pointer(void *x)
{
show_bytes((byte_pointer)&x, sizeof(x));
}
void test_show_bytes(int val)
{
int ival = val;
float fval = (float)val;
int *pval = &val;
show_int(ival);
show_float(fval);
show_pointer(pval);
}
test_show_bytes(0x01234567);
可以得到結果67 45 23 01
b4 a2 91 4b
d4 fb 2d 00
應用場景一 網絡數據傳輸
對於程序員來說選擇,機器所使用的字節排列順序是不可見的,無論爲那種排列編程都會得到相同的結果。但是在有些時候字節順序會成爲問題。首先是在不同類型的機器之間通過網絡傳送二進制數據時,一個常見的問題是當小端法機器產生的數據傳輸到大端法機器時接受程序裏的字節成了反序的。爲了避免由於這個原因而產生錯誤網絡程序的代碼編寫必須遵守已建立的關於字節順序的規則,以確保發送方機器將他的內部表示轉換成網絡標準,而接受方將網絡標準轉化爲它的內部表示。
應用場景二 機器碼與某些破解工作
在查看和更改機器級代碼時需要注意顯示的內存地址之類的值可能是以大端法或者小端法排列的。另外在某些破解時也要注意機器採用的是大端法或者小端法,如在安裝黑蘋果時修改DSDT文件時,裏面的值大多使用小端法排列