或許你曾經仔細了解過什么是大端小端,也動手編寫了測試手頭上的機器上是大端還是小端的程序,甚至還編寫了大端小端轉換程序;但過了一段時間之后,當你再看到大端和小端這兩個字眼,你的腦中很快浮起了自己曾經做過的工作,卻總是想不起究竟哪種是大端、哪種是小端,然后又去查以前寫的記錄?更讓人不快的是,這種經歷反反復復,讓你十分困擾。如果你和以前的筆者一樣,有過這種不快的經歷,那么這篇文章希望能幫你徹底解決這個苦惱,讓你徹底記住它們。 如果你在工作中經常使用到大端和小端以至于對它們十分熟悉,或者你的記憶力在保持時間的長度和精準度上都十分優(yōu)秀,以至于不需要借助其他的方法,那么這篇文章不適合你。 如果你在看這篇文章前完全不知道什么是大端和小端,那么可以參考本文的附錄或者其他的博文,相關的介紹非常之多,而附錄提供了一個很常見解釋和一段測試程序,然后再來看正文。 為了幫助記憶,理解是必要的;而記憶的目的,也就是為什么要記住它,是更重要的。或許你會問,先了解概念,用的時候再查,不行么?其實我之前也是這么認為的。大端和小端這兩個名詞,你會在很多有關網絡編程、系統(tǒng)設計、甚至是代碼寫作的書上看到,而且它也是很多公司的筆試題、面試題熱門內容,可見它在一些領域是很常用。如果等到你用的時候再查,一方面要降低你的工作效率,另一方面,應試的時候也不是你想查就能查的;其實最主要的是,在掌握規(guī)律后,記住它們并不困難。 現在先來理解這對概念,大端和小端這兩個令人迷惑的術語究竟是如何產生的?《程序設計實踐》第9章中提到,“大端”和“小端”可以追溯到1726年的Jonathan Swift的《格列佛游記》,其中一篇講到有兩個國家因為吃雞蛋究竟是先打破較大的一端還是先打破較小的一端而爭執(zhí)不休,甚至爆發(fā)了戰(zhàn)爭。1981年10月,Danny Cohen的文章《論圣戰(zhàn)以及對和平的祈禱》(On holy wars and a plea for peace)將這一對詞語引入了計算機界。這么看來,所謂大端和小端,也就是big-endian和little-endian,其實是從描述雞蛋的部位而引申到計算機地址的描述,也可以說,是從一個俚語衍化來的計算機術語。稍有些英語常識的人都會知道,如果單靠字面意思來理解俚語,那是很難猜到它的正確含義的。在計算機里,對于地址的描述,很少用“大”和“小”來形容;對應地,用的更多的是“高”和“低”;很不幸地,這對術語直接按字面翻譯過來就成了“大端”和“小端”,讓人產生迷惑也不是很奇怪的事了。 不過給我啟發(fā)的是,在裘宗燕翻譯的《程序設計實踐》里,這對術語并沒有翻譯為“大端”和小端,而是“高尾端”和“低尾端”,這就好理解了:如果把一個數看成一個字符串,比如11223344看成"11223344",末尾是個'\0','11'到'44'個占用一個存儲單元,那么它的尾端很顯然是44,前面的高還是低就表示尾端放在高地址還是低地址,它在內存中的放法非常直觀,如下圖:
“高/低尾端”比“大/小端”更不容易讓人迷惑。但是根據個人經驗,在市面上的書籍、網絡上的各種資料中,很遺憾,前者已經很少見了,多見的是后者。好在這兩對形容詞中,恰好“高”和“大”對應,“低”和“小”對應;既然高尾端對應的是大端,低尾端對應的是小端,那么當你再見到大端和小端這一對術語,就可以在腦中把它們轉化成高尾端和低尾端,這時憑著之前的理解,甚至不用回憶,想著高低的字面含義就能回想起它們的含義。但是很奇怪的是,同樣是裘宗燕翻譯的《編程原本》(Elements of Programming),卻把big-endian翻譯成大尾格式(第一章)。 理解之后,總結一下,記憶的方法是:
稍一思索什么是“高”、什么是"低","尾端"又是什么,問題迎刃而解,再不用擔心被“大端”和“小端”迷惑。用這種方式,是時候放棄原先的死記硬背和容易把自己繞進去而發(fā)生迷惑的理解了。
附錄:什么是“大端”和“小端”及一段測試本機大端還是小端的代碼 (這段文字是《UNIX網絡編程·卷一》的關于這個概念的概括;不僅限于這本書,很多計算機書籍都是這么介紹這個概念的,你會在和計算機相關不同領域的書中遇到它們。盡管很令人疑惑,但是在閱讀正文前,你最好對這兩個詞語的概念有所理解。當然,如果你以前向正文中描述的一樣接觸過它們,那就不必讀這一部分了。讀完后你會發(fā)現,你雖然理解了含義,但很容易忘掉,這時你就可以看正文部分了) 對于一個由2個字節(jié)組成的16位整數,在內存中存儲這兩個字節(jié)有兩種方法:一種是將低序字節(jié)存儲在起始地址,這稱為小端(little-endian)字節(jié)序;另一種方法是將高序字節(jié)存儲在起始地址,這稱為大端(big-endian)字節(jié)序。
在圖中,頂部表明內存地址增長方向從右到左,在底部標明內存地址增長的方向為從左到右。并且還標明最高有效位(most significant bit,MSB)是這個16位值最左邊一位,最低有效位(least significant bit, LSB)是這個16位值最右邊一位。術語“小端”和“大端”表示多個字節(jié)值的哪一端(小端或大端)存儲在該值的起始地址。 這兩種字節(jié)序沒有標準可循,都有系統(tǒng)在使用。把某個給定系統(tǒng)所用的字節(jié)序稱為主機字節(jié)序,可以用以下程序輸出主機字節(jié)序。方法是在一個短整數變量中存放2字節(jié)的值0x0102,然后查看它的連續(xù)字節(jié)c[0](對應上圖地址A)和c[1](對應上圖地址A+1),以此確定字節(jié)序。 #include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
union {
short s;
char c[sizeof(short)];
} un;
un.s = 0x0102;
if(sizeof(short)==2) {
if(un.c[0]==1 && un.c[1] == 2)
printf("big-endian\n");
else if (un.c[0] == 2 && un.c[1] == 1)
printf("little-endian\n");
else
printf("unknown\n");
} else
printf("sizeof(short)= %d\n",sizeof(short));
exit(0);
}
|
|