日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

字节序、位序

發布時間:2023/12/10 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字节序、位序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

字節序

??? 字節序,又稱端序、尾序,英文單詞為Endian,該單詞來源于于喬納森·斯威夫特的小說《格列佛游記》,小說中的小人國因為吃雞蛋的問題而內戰,戰爭開始是由于以下的原因:我們大家都認為,吃雞蛋前,原始的方法是打破雞蛋較大的一端??墒钱斀窕实鄣淖娓感r候吃雞蛋,一次按古法打雞蛋時碰巧將一個手指弄破了,因此他的父親,當時的皇帝,就下了一道敕令,命令全體臣民吃雞蛋時打破雞蛋較小的一端,違令者重罰。老百姓們對這項命令極為反感。歷史告訴我們,由此曾發生過六次叛亂,其中一個皇帝送了命,另一個丟了王位…關于這一爭端,曾出版過幾百本大部著作,不過大端派的書一直是受禁的,法律也規定該派的任何人不得做官。?1980年,Danny Cohen在其著名的論文"On Holy Wars and a Plea for Peace"中,為平息一場關于字節該以什么樣的順序傳送的爭論,而引用了該詞。

?????????在計算機科學領域中,字節序是指存放多字節數據的字節(byte)的順序,典型的情況是整數在內存中的存放方式和網絡傳輸的傳輸順序。有時候也可以用指位序(bit)。為了更好地理解,先看下面這段小程序,這個程序是把一個包含4位數字的字符串轉換為16進制整數來存儲,16進制整數的每一個字節存儲一位數字字符。比如:”1234”,轉換成16進制整數0x01020304。

程序1清單:

#include?<stdio.h>

#include?<conio.h>

?

int?main( )

{

?????char?input[4] = {0};

?????int?integer???= 0;

?????int?i;

?????printf("/r/n請輸入一個位數,每一位的范圍是從到0到9/r/n");

?????for(i = 0; i < 4; i++)

?????{

?????????input[i] = getch();

?????????if(input[i] >?'9'?|| input[i] <?'0')

?????????{

??????????????printf("input error!/r/n");

??????????????return?1;

?????????}

?????????putch(input[i]);

?????}

????getch();

?????putch('/n');

?

?????for(i = 0; i < 4; i++)

?????{

?????????input[i] = input[i] -?'0';

?????}

?

?????memcpy((void*)&integer, (void*)input, 4);

?

?????printf("轉換后的進制數是:0x%08x/r/n", integer);

?

?????getch();

?

?????return?0;

}

?

現在來分析一下這段代碼

首先,定義了一個字符數組input,用來接收用戶輸入的4個數字字符;

第二,把4個字符數字轉換成對應的數字;

第三,把轉換的數字復制到整型變量integer中;

最后在屏幕上打印。

如果在PPC或者ARM的機器上編譯運行這個程序,那么會在屏幕上打印出結果:0x01020304,這與我們的預期一致;但是在X86的機器上則打印出的結果是:0x04030201。這個令人驚訝的結果正是字節序問題引起。下面來詳細談談這個問題。

?

????從計算機誕生之后,就有幾種不同的字節序,典型的是大端序(big endian)和小端序(little endian),當然還有不常見的混合序(middle endian)。這些用來都是描述多字節數據在內存中的存放方式的。以上面的16進制數0x01020304為例,在計算機中需要用4個字節來保存它,’01’, ’02’,’03’,’04’各占一個字節。按照人類的計數習慣,最左邊的’01’,稱之為最高有效位(MSB,Most Significant Byte,它具有最高權重);最右邊的’04’稱之為最低有效位(LSB, Least Significant Byte,他具有最低權重);在計算機中需要用4個字節來保存它,其中’01’, ’02’,’03’,’04’各占一個字節。大端序的計算機保存這個數值時,按照從低地址到高地址的順序分別保存MSB到LSB四個字節,0x01020304的存儲情況如下圖所示:

?

而小端序的計算機則以相反的順序來保存它,如下圖所示:

?

?

可以看到,在小端序的計算機中,0x01020304的保存順序恰好與上面的程序1中相反,這就是最后輸出結果為0x04030201的原因;大端序的計算機中兩者保存順序一致,所以打印正確。

?

??? 我們可以在VC集成環境中來驗證上面的分析。在VS2005中調試下面的小程序,在return語句處設置斷點,斷住后打開內存窗口查看&i處的內容??梢灾庇^的看到在x86(小端序)的機器上整數的存放方式。

程序2清單:

#include?<stdio.h>

int?main()

{

?????int?i = 0x01020304;

?????printf("i = %#x/r/n",i);

?????return?0;

}

?

?

?

?

?

再看看如何才能讓程序1在大端序和小端序的機器上都能正確執行呢?一個辦法就是利用預編譯宏,針對不同的機器定義定義不同的數據結構。下面是一個例子:

程序3清單:

#include?<stdio.h>

#include?<conio.h>

?

typedef?union

{

?????struct{

#ifdef?BIG_ENDIAN

?????char msb;

?????char midb1;

?????char midb2;

?????char lsb;

#else

?????char?lsb;

?????char?midb2;

?????char?midb1;

?????char?msb;

#endif

?????} bytes;

?????int??var;

} INTEGER;

?

int?main()

{

?????int??i??????????= 0;

?????char?input[5]???= {0};

?????INTEGER integer = {0};

?

?????printf("/r/n請輸入一個位數,每一位的范圍是從到到/r/n");

?????for(i = 0; i < 4; i++)

?????{

?????????input[i] = getch();

?????????if(input[i] >?'9'?|| input[i] <?'0')

?????????{

??????????????printf("input error!/r/n");

??????????????return?1;

?????????}

?????????putch(input[i]);

?????}

????getch();

?????putch('/n');

?

?????integer.bytes.msb???= input[0] -?'0';

?????integer.bytes.midb1 = input[1] -?'0';

?????integer.bytes.midb2 = input[2] -?'0';

?????integer.bytes.lsb???= input[3] -?'0';

?

?????printf("轉換后的進制數是:0x%08x/r/n", integer.var);

?

?????getch();

?

?????return?0;

}

可以看到,這段代碼定義了兩套數據結構,通過BIG_ENDIAN這個宏定義來決定使用哪一套數據結構。這是個笨拙卻有效的方法。下面這個例子則漂亮一些:

程序4清單

#include?<stdio.h>

#include?<conio.h>

#include?<memory.h>

#include?<winsock2.h>

?

int?main( )

{

?????char?input[4] = {0};

?????int?integer???= 0;

?????int?i;

?????printf("/r/n請輸入一個位數,每一位的范圍是從到到/r/n");

?????for(i = 0; i < 4; i++)

?????{

?????????input[i] = getch();

?????????if(input[i] >?'9'?|| input[i] <?'0')

?????????{

??????????????printf("input error!/r/n");

??????????????return?1;

?????????}

?????????putch(input[i]);

?????}

????getch();

?????putch('/n');

?

?????for(i = 0; i < 4; i++)

?????{

?????????input[i] = input[i] -?'0';

?????}

?

?????memcpy((void*)&integer, (void*)input, 4);

?

?????integer = ntohl(integer);

?

?????printf("轉換后的進制數是:0x%08x/r/n", integer);

?

?????getch();

?

?????return?0;

}

這個程序利用了大端序與人類書寫習慣一致的特點,通過ntohl函數將整數進行轉換。這個函數的功能是將網絡序轉換成主機序,在大端機器上它什么也不做,在小端機器上它會將輸入參數的值轉換成小端序的值。在windows環境下鏈接時別忘了將Ws2_32.lib庫添加進來。

?

主機序和網絡序

主機序就是指主機的端序。

網絡字節序(網絡序)指多字節數據在網絡傳輸中的順序,TCP協議規定網絡序是大端序,即高字節先發送。因此大端序的機器接受到的數據可直接使用,小端序機器則需要轉換后使用。BSD socket API中定義了一組轉換函數,用于16和32bit整數在網絡序和本機字節序之間的轉換。htonl,htons用于本機序轉換到網絡序;ntohl,ntohs用于網絡序轉換到本機序。一般來說,為了保證程序的可移植性,編寫代碼時,發送的數據需要使用htonl、htons轉換,接收到的數據要使用ntohl、ntohs轉換。

注意:不存在對單字節整數進行轉換的函數”ntohc”和”htonc”!

位序

?????????位序,一般用于描述串行設備的傳輸順序。一般說來大部分硬件都是采用小端序(先傳低位),因此,對于一個字節數據,大部分機器上收發的順序都一樣,不會有問題,這就是為什么沒有針對單字節數據的API接口”ntohc”和”htonc”。當然,也有例外,比如-I2C協議就是采用了大端序。這些細節只有在網絡協議的數據鏈路層底端才會碰到,對一般的程序員來說很少涉及。

?????????但是在C語言中存在一種特殊的數據結構:位域。它的存在,使得C程序員能方便地進行位操作(比如在網絡協議中經常出現1bit或者多bit的標示位,它們不是一個完整的字節)。但同時也引起一些難以察覺的問題,這些問題的根源仍然是前面提到的端序。

?

?????????與字節序一樣,一個字節中的8個bit順序在不同端序的機器上并不相同。大端機器上從低地址到高地址順尋分別是msb->lsb,如下圖:

?

?

小端序的機器上則正好相反

?

現代計算機的最小存儲單位是BYTE,無法對bit尋址,因此我們無法直接觀察每個字節內部bit的順序。但是我們仍然可以通過位域來間接觀察字節內部bit順序,以印證上面的說法。

在C語言中,位域與結構體類似,其語法規定:先聲明的成員位于低地址,后聲明的成員位于高地址。那么下面的位域中:

typedef?struct?OneByte

{

?????bt0 : 1;

?????bt1 : 1;

?????bt2 : 1;

?????bt3 : 1;

?????bt4 : 1;

?????bt5 : 1;

?????bt6 : 1;

?????bt7 : 1;

}

成員bt0就位于一個字節中最低地址bit0處,成員bt7就位于一個字節的最地址bit7處。

?

我們看看下面的程序。

#include?<stdio.h>

?

typedef?struct?OneByte

{

?????char?bt0 : 1;

?????char?bt1 : 1;

?????char?bt2 : 1;

?????char?bt3 : 1;

?????char?bt4 : 1;

?????char?bt5 : 1;

?????char?bt6 : 1;

?????char?bt7 : 1;

} ONE_BYTE;

?

int?main()

{

?????ONE_BYTE onebyte = {0};

????

?????onebyte.bt7 = 1;

?

?????printf("onebyte = %#x/r/n", *((unsigned?char?*)&onebyte));

?

?????return?0;

}

?

當bt7賦值為1后,onebyte在內存中是這個樣子的:

?

而在VC2005中編譯運行的結果如下:

?

0x80轉換成二進制是1000 0000。由于在X86(小端序)中,高地址bit7是msb,因此onebyte的值是0x80了;這就證實了前面的說法。?相應的如果是在大端序計算機中,bit7是lsb,則onebyte的值是0x01。

?

?

?

未完待續

總結

以上是生活随笔為你收集整理的字节序、位序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。