1. 程式人生 > >【轉】輕鬆記住大端小端的含義(附對大端和小端的解釋)

【轉】輕鬆記住大端小端的含義(附對大端和小端的解釋)

 轉自:http://www.cnblogs.com/wuyuegb2312/archive/2013/06/08/3126510.html

       或許你曾經仔細瞭解過什麼是大端小端,也動手編寫了測試手頭上的機器上是大端還是小端的程式,甚至還編寫了大端小端轉換程式;但過了一段時間之後,當你再看到大端和小端這兩個字眼,你的腦中很快浮起了自己曾經做過的工作,卻總是想不起究竟哪種是大端、哪種是小端,然後又去查以前寫的記錄?更讓人不快的是,這種經歷反反覆覆,讓你十分困擾。如果你和以前的筆者一樣,有過這種不快的經歷,那麼這篇文章希望能幫你徹底解決這個苦惱,讓你徹底記住它們。 

  如果你在工作中經常使用到大端和小端以至於對它們十分熟悉,或者你的記憶力在保持時間的長度和精準度上都十分優秀,以至於不需要藉助其他的方法,那麼這篇文章不適合你。

  如果你在看這篇文章前完全不知道什麼是大端和小端,那麼可以參考本文的附錄或者其他的博文,相關的介紹非常之多,而附錄提供了一個很常見解釋和一段測試程式,然後再來看正文。

  為了幫助記憶,理解是必要的;而記憶的目的,也就是為什麼要記住它,是更重要的。或許你會問,先了解概念,用的時候再查,不行麼?其實我之前也是這麼認為的。大端和小端這兩個名詞,你會在很多有關網路程式設計、系統設計、甚至是程式碼寫作的書上看到,而且它也是很多公司的筆試題、面試題熱門內容,可見它在一些領域是很常用。如果等到你用的時候再查,一方面要降低你的工作效率,另一方面,應試的時候也不是你想查就能查的;其實最主要的是,在掌握規律後,記住它們並不困難。

  現在先來理解這對概念,大端和小端這兩個令人迷惑的術語究竟是如何產生的?《程式設計實踐》第9章中提到,“大端”和“小端”可以追溯到1726年的Jonathan Swift的《格列佛遊記》,其中一篇講到有兩個國家因為吃雞蛋究竟是先打破較大的一端還是先打破較小的一端而爭執不休,甚至爆發了戰爭。1981年10月,Danny Cohen的文章《論聖戰以及對和平的祈禱》(On holy wars and a plea for peace)將這一對詞語引入了計算機界。這麼看來,所謂大端和小端,也就是big-endian和little-endian,其實是從描述雞蛋的部位而引申到計算機地址的描述,也可以說,是從一個俚語衍化來的計算機術語。稍有些英語常識的人都會知道,如果單靠字面意思來理解俚語,那是很難猜到它的正確含義的。在計算機裡,對於地址的描述,很少用“大”和“小”來形容;對應地,用的更多的是“高”和“低”;很不幸地,這對術語直接按字面翻譯過來就成了“大端”和“小端”,讓人產生迷惑也不是很奇怪的事了。

  不過給我啟發的是,在裘宗燕翻譯的《程式設計實踐》裡,這對術語並沒有翻譯為“大端”和小端,而是“高尾端”“低尾端”,這就好理解了:如果把一個數看成一個字串,比如11223344看成"11223344",末尾是個'\0','11'到'44'個佔用一個儲存單元,那麼它的尾端很顯然是44,前面的高還是低就表示尾端放在高地址還是低地址,它在記憶體中的放法非常直觀,如下圖:

  “高/低尾端”比“大/小端”更不容易讓人迷惑。但是根據個人經驗,在市面上的書籍、網路上的各種資料中,很遺憾,前者已經很少見了,多見的是後者。好在這兩對形容詞中,恰好“高”和“大”對應,“低”和“小”對應;既然高尾端對應的是大端,低尾端對應的是小端,那麼當你再見到大端和小端這一對術語,就可以在腦中把它們轉化成高尾端和低尾端,這時憑著之前的理解,甚至不用回憶,想著高低的字面含義就能回想起它們的含義。但是很奇怪的是,同樣是裘宗燕翻譯的《程式設計原本》(Elements of Programming),卻把big-endian翻譯成大尾格式(第一章)。

  理解之後,總結一下,記憶的方法是:

(資料看成字串)大端——高尾端,小端——低尾端

  稍一思索什麼是“高”、什麼是"低","尾端"又是什麼,問題迎刃而解,再不用擔心被“大端”和“小端”迷惑。用這種方式,是時候放棄原先的死記硬背和容易把自己繞進去而發生迷惑的理解了。

附錄:什麼是“大端”和“小端”及一段測試本機大端還是小端的程式碼

(這段文字是《UNIX網路程式設計·卷一》的關於這個概念的概括;不僅限於這本書,很多計算機書籍都是這麼介紹這個概念的,你會在和計算機相關不同領域的書中遇到它們。儘管很令人疑惑,但是在閱讀正文前,你最好對這兩個詞語的概念有所理解。當然,如果你以前向正文中描述的一樣接觸過它們,那就不必讀這一部分了。讀完後你會發現,你雖然理解了含義,但很容易忘掉,這時你就可以看正文部分了)

  對於一個由2個位元組組成的16位整數,在記憶體中儲存這兩個位元組有兩種方法:一種是將低序位元組儲存在起始地址,這稱為小端(little-endian)位元組序;另一種方法是將高序位元組儲存在起始地址,這稱為大端(big-endian)位元組序。

  

  在圖中,頂部表明記憶體地址增長方向從右到左,在底部標明記憶體地址增長的方向為從左到右。並且還標明最高有效位(most significant bit,MSB)是這個16位值最左邊一位,最低有效位(least significant bit, LSB)是這個16位值最右邊一位。術語“小端”和“大端”表示多個位元組值的哪一端(小端或大端)儲存在該值的起始地址。

  這兩種位元組序沒有標準可循,都有系統在使用。把某個給定系統所用的位元組序稱為主機位元組序,可以用以下程式輸出主機位元組序。方法是在一個短整數變數中存放2位元組的值0x0102,然後檢視它的連續位元組c[0](對應上圖地址A)和c[1](對應上圖地址A+1),以此確定位元組序。

複製程式碼
#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);
}
複製程式碼

  補充:常用處理器的位元組序,X86系列處理器、ARM處理器是低尾端(不同的系統有所區別 ),而MIPS、PPC如IBM半導體和Freescale的PowerPC處理器是高尾端處理器。而網絡位元組序都是高尾端處理器