大小端問題

大小端問題

    最近工作中,有兩次遇到大小端問題,所以花時間寫這篇日誌,總結一下。


1.      實際需求
         (1) 前段時間寫了一個修復損壞的gzip文件的tool,在Linux Server上編譯運行沒有問題。但是在Solaris Server上運編譯運行,結果總是和預期的不一致,跟蹤發現是由大小端問題導致的;
        (2) 最近在寫一個跨平臺的編譯腳本,編譯參數裏有目標可執行程序運行平臺大小端這個參數;

2.     大小端解析
        端模式出自Jonathan Swift書寫的《格列佛遊記》一書,這本書根據將雞蛋敲開的方法不同將所有的人分爲兩類,從圓頭開始將雞蛋敲開的人被歸爲Big Endian,從尖頭開始將雞蛋敲開的人被歸爲Littile Endian。小人國的內戰就源於吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開。
        在計算機業Big Endian和Little Endian也幾乎引起一場戰爭。在計算機業界,Endian表示數據在存儲器中的存放順序。
        大端:高位存在低地址,低位存在高地址;
        小端:高位存在高地址,低位存在低地址;(intel的x86,ARM普遍都是屬於小端)


        舉個例子,從內存地址0x0000開始有以下數據
        0x0000    0x12
        0x0001    0x34
        0x0002    0xab
        0x0003    0xcd

    
        如果我們去讀取一個地址爲0x0000的四個字節變量:
                若字節序爲big-endian,則讀出結果爲0x1234abcd;
                若字節序位little-endian,則讀出結果爲0xcdab3412.

        如果我們將0x1234abcd寫入到以0x0000開始的內存中,則結果爲:
                         big-endian      little-endian
        0x0000          0x12                  0xcd
        0x0001          0x23                  0xab
        0x0002          0xab                  0x34
        0x0003          0xcd                  0x12

        
        Intelx86系列以及ARM系列CPU都是little-endian的字節序.

3.    大小端問題的解決

       (1) 下面貼一個很簡單的判斷大小端的函數

int checkCPUendian()//返回1,爲小端;反之,爲大端;
{
    union
    {
        unsigned int  a;
        unsigned char b;
    }c;
    c.a = 1;
    return 1 == c.b;
}

       (2) 大端模式處理器的字節序到網絡字節序不需要轉換,此時ntohs(n)=n,ntohl =n;而小端模式處理器的字節序到網絡字節必須要進行轉換(同理,有時候需要將大端字節順序轉換成小端字節順序,也用這個函數,因爲這個函數本來就是用來顛倒字節順序的),轉換如下:

  

#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)


   #define htons(A)  (A)
   #define htonl(A)  (A)
   #define ntohs(A)  (A)
   #define ntohl(A)  (A)


#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)


   #define htons(A)  ((((uint16_t)(A) & 0xff00) >> 8 ) | \\
                      (((uint16_t)(A) & 0x00ff) << 8 ))
   #define htonl(A)  ((((uint32_t)(A) & 0xff000000) >> 24)  | \\
                      (((uint32_t)(A) & 0x00ff0000) >> 8 )  | \\
                      (((uint32_t)(A) & 0x0000ff00) << 8 )  | \\
                      (((uint32_t)(A) & 0x000000ff) << 24))
   #define ntohs     htons
   #define ntohl     htohl


#else


   #error Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both.


#endif

大小端問題:http://blog.csdn.net/yasaken/article/details/7243757

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章