位元組序問題

來源:互聯網
上載者:User

一、位元組序定義
位元組序,顧名思義位元組的順序,再多說兩句就是大於一個位元組類型的資料在記憶體中的存放順序(一個位元組的資料當然就無需談順序的問題了)。

其實大部分人在實際的開發中都很少會直接和位元組序打交道。唯有在跨平台以及網路程式中位元組序才是一個應該被考慮的問題。

在所有的介紹位元組序的文章中都會提到位元組序分為兩類:Big-Endian和Little-Endian。引用標準的Big-Endian和Little-Endian的定義如下:
a) Little-Endian就是低位位元組排放在記憶體的低地址端,高位位元組排放在記憶體的高地址端。
b) Big-Endian就是高位位元組排放在記憶體的低地址端,低位位元組排放在記憶體的高地址端。
c) 網路位元組序:TCP/IP各層協議將位元組序定義為Big-Endian,因此TCP/IP協議中使用的位元組序通常稱之為網路位元組序。

其實我在第一次看到這個定義時就很糊塗,看了幾個例子後也很是朦朧。什麼高/低地址端?又什麼高低位?翻閱了一些資料後略有心得。

二、高/低地址與高低位元組
首先我們要知道我們C程式映像中記憶體的空間布局情況:在《C專家編程》中或者《Unix環境進階編程》中有關於記憶體空間布局情況的說明,大致如:
----------------------- 最高記憶體位址 0xffffffff
 | 棧底
 .
 .              棧
 .
  棧頂
-----------------------
 |
 |
/|/

NULL (空洞) 

/|/
 |
 |
-----------------------
                堆
-----------------------
未初始化的資料
----------------(統稱資料區段)
初始化的資料
-----------------------
本文段(程式碼片段)
----------------------- 最低記憶體位址 0x00000000

以為例如果我們在棧上分配一個unsigned char buf[4],那麼這個陣列變數在棧上是如何布局的呢[注1]?看:
棧底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低地址)

現在我們弄清了高低地址,接著我來弄清高/低位元組,如果我們有一個32位無符號整型0x12345678(呵呵,恰好是把上面的那4個位元組buf看成一個整型),那麼高位是什麼,低位又是什麼呢?其實很簡單。在十進位中我們都說靠左邊的是高位,靠右邊的是低位,在其他進位也是如此。就拿 0x12345678來說,從高位到低位的位元組依次是0x12、0x34、0x56和0x78。

高低地址和高低位元組都弄清了。我們再來回顧一下Big-Endian和Little-Endian的定義,並用圖示說明兩種位元組序:
以unsigned int value = 0x12345678為例,分別看看在兩種位元組序下其儲存情況,我們可以用unsigned char buf[4]來表示value:
Big-Endian: 低地址存放高位,如:
棧底 (高地址)
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
棧頂 (低地址)

Little-Endian: 低地址存放低位,如:
棧底 (高地址)
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
---------------
棧頂 (低地址)

在現有的平台上Intel的X86採用的是Little-Endian,而像Sun的SPARC採用的就是Big-Endian。

三、例子
測試平台: Sun SPARC Solaris 9和Intel X86 Solaris 9
我們的例子是這樣的:在使用不同位元組序的平台上使用相同的程式讀取同一個二進位檔案的內容。
產生二進位檔案的程式如下:
/* gen_binary.c */
int main() {
        FILE    *fp = NULL;
        int     value = 0x12345678;
        int     rv = 0;

        fp = fopen("temp.dat", "wb");
        if (fp == NULL) {
                printf("fopen error/n");
                return -1;
        }

        rv = fwrite(&value, sizeof(value), 1, fp);
        if (rv != 1) {
                printf("fwrite error/n");
                return -1;
        }

        fclose(fp);
        return 0;
}

讀取二進位檔案的程式如下:
int main() {
        int             value   = 0;
        FILE         *fp     = NULL;
        int             rv      = 0;
        unsigned        char buf[4];

        fp = fopen("temp.dat", "rb");
        if (fp == NULL) {
                printf("fopen error/n");
                return -1;
        }

        rv = fread(buf, sizeof(unsigned char), 4, fp);
        if (rv != 4) {
                printf("fread error/n");
                return -1;
        }

        memcpy(&value, buf, 4); // or value = *((int*)buf);
        printf("the value is %x/n", value);

        fclose(fp);
        return 0;
}

測試過程:
(1) 在SPARC平台下產生temp.dat檔案
在SPARC平台下讀取temp.dat檔案的結果:
the value is 12345678

在X86平台下讀取temp.dat檔案的結果:
the value is 78563412

(1) 在X86平台下產生temp.dat檔案
在SPARC平台下讀取temp.dat檔案的結果:
the value is 78563412

在X86平台下讀取temp.dat檔案的結果:
the value is 12345678

[注1]
buf[4]在棧的布局我也是通過例子程式得到的:
int main() {
        unsigned char buf[4];

        printf("the buf[0] addr is %x/n", buf);
        printf("the buf[1] addr is %x/n", &buf[1]);

        return 0;
}
output:
SPARC平台:
the buf[0] addr is ffbff788
the buf[1] addr is ffbff789
X86平台:
the buf[0] addr is 8047ae4
the buf[1] addr is 8047ae5

兩個平台都是buf[x]所在地址高於buf[y] (x > y)。

 

 

20090824補充:

1、網路與主機位元組轉換函式:htons ntohs htonl ntohl (s 就是short l是long h是host n是network)
2、不同的CPU上運行不同的作業系統,位元組序也是不同的,參見下表。
處理器     作業系統     位元組排序
Alpha     全部     Little endian
HP-PA     NT     Little endian
HP-PA     UNIX     Big endian
Intelx86     全部     Little endian <-----x86系統是小端位元組序系統
Motorola680x()     全部     Big endian
MIPS     NT     Little endian
MIPS     UNIX     Big endian
PowerPC     NT     Little endian
PowerPC     非NT     Big endian   <-----PPC系統是大端位元組序系統
RS/6000     UNIX     Big endian
SPARC     UNIX     Big endian
IXP1200 ARM核心     全部     Little endian

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.