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翻譯成大尾格式(第一章)。

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

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

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


附加一段測試大小端的C語言程式碼:

#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);
}