大小端模式

2021-07-08 17:18:24 字數 4384 閱讀 5530

關於大端小端名詞的由來,有乙個有趣的故事,來自於jonathan swift的《格利佛遊記》:lilliput和blefuscu這兩個強國在過去的36個月中一直在苦戰。戰爭的原因:大家都知道,吃雞蛋的時候,原始的方法是打破雞蛋較大的一端,可以那時的皇帝的祖父由於小時侯吃雞蛋,按這種方法把手指弄破了,因此他的父親,就下令,命令所有的子民吃雞蛋的時候,必須先打破雞蛋較小的一端,違令者重罰。然後老百姓對此法令極為反感,期間發生了多次叛亂,其中乙個皇帝因此送命,另乙個丟了王位,產生叛亂的原因就是另乙個國家blefuscu的國王大臣煽動起來的,叛亂平息後,就逃到這個帝國避難。據估計,先後幾次有11000餘人情願死也不肯去打破雞蛋較小的端吃雞蛋。這個其實諷刺當時英國和法國之間持續的衝突。danny cohen一位網路協議的開創者,第一次使用這兩個術語指代位元組順序,後來就被大家廣泛接受。

big-endian和little-endian的定義如下:

1) little-endian就是低位位元組排放在記憶體的低位址端,高位位元組排放在記憶體的高位址端。

2) big-endian就是高位位元組排放在記憶體的低位址端,低位位元組排放在記憶體的高位址端。

舉乙個例子,比如數字0x12 34 56 78在記憶體中的表示形式為:

1)大端模式:

低位址 -----------------> 高位址

0x12  |  0x34  |  0x56  |  0x78

2)小端模式:

低位址 ------------------> 高位址

0x78  |  0x56  |  0x34  |  0x12

可見,大端模式和字串的儲存模式類似。

3)下面是兩個具體例子:

16bit寬的數0x1234在little-endian模式(以及big-endian模式)cpu記憶體中的存放方式(假設從位址0x4000開始存放)為:

記憶體位址

小端模式存放內容

大端模式存放內容

0x4000

0x34

0x12

0x4001

0x12

0x34

32bit寬的數0x12345678在little-endian模式以及big-endian模式)cpu記憶體中的存放方式(假設從位址0x4000開始存放)為:

記憶體位址

小端模式存放內容

大端模式存放內容

0x4000

0x78

0x12

0x4001

0x56

0x34

0x4002

0x34

0x56

0x4003

0x12

0x78

4)大端小端沒有誰優誰劣,各自優勢便是對方劣勢:

小端模式 :強制轉換資料不需要調整位元組內容,1、2、4位元組的儲存方式一樣。

大端模式 :符號位的判定固定為第乙個位元組,容易判斷正負。

以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) -- 低位

--------------

低位址

這是因為在計算機系統中,我們是以位元組為單位的,每個位址單元都對應著乙個位元組,乙個位元組為8bit。但是在c語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對於位數大於8位的處理器,例如16位或者32位的處理器,由於暫存器寬度大於乙個位元組,那麼必然存在著乙個如果將多個位元組安排的問題。因此就導致了大端儲存模式和小端儲存模式。例如乙個16bit的short型x,在記憶體中的位址為0x0010,x的值為0x1122,那麼0x11為高位元組,0x22為低位元組。對於大端模式,就將0x11放在低位址中,即0x0010中,0x22放在高位址中,即0x0011中。小端模式,剛好相反。我們常用的x86結構是小端模式,而keil c51則為大端模式。很多的arm,dsp都為小端模式。有些arm處理器還可以由硬體來選擇是大端模式還是小端模式。

可以編寫乙個小的測試程式來判斷機器的位元組序:

[cpp]view plain

copy

intchecksystem()  

c;  

c.i = 1;  

return

(c.ch==1); 

//true 1 表示小端模式

}  

或者用下面這個**也可以測試大小端模式:

[cpp]view plain

copy

bool

isbigendian()  

num;  

num.a = 0x1234;  

if( num.b == 0x12 )  

return

false

;  }  

一般作業系統都是小端,而通訊協議是大端的。

常見cpu的位元組序

big endian : powerpc、ibm、sun

little endian : x86、dec

arm既可以工作在大端模式,也可以工作在小端模式。

常見檔案的位元組序

adobe ps – big endian

bmp – little endian

dxf(autocad) – variable

gif – little endian

jpeg – big endian

macpaint – big endian

rtf – little endian

乙個例子,請看下面的輸出結果是多少?我的機器用上面的**測試後是小端模式。

[cpp]view plain

copy

intmain(

void

)  ;  

int* ptr1 = (

int*)(&a+1);  

int* ptr2 = (

int*)((

int)a+1);  

printf("%x,%x\n"

,ptr1[-1],*ptr2);  

printf("%d,%d\n"

,ptr1[-1],*ptr2);  

system("pause"

);  

}  

先把結果拿出來

經過除錯陣列a的首位址為0x002dfb80, &a+1表示把指標從a的首位址處移a陣列大小,即移動5個int的大小(20)。20的16進製為0x14。所有&a+1的位址為0x002dfb80+0x14=0x002dfb94, 即ptr1的位址為0x002dfb94,ptr1[-1]就是位址0x002dfb94減乙個int的大小,即ptr1[-1]=0x002dfb94-0x4=0x002dfb90。這裡0x002dfb90的位址正好是a[4]的位址,所以結果是5。

for ptr2:

(int)a+1表示的是先把a轉換為整形,然後再加1。最後把加1後的值作為乙個指向int的指標。這裡a本來就是陣列的首位址。前面提到a的首位址為0x002dfb80,所有ptr2的位址為0x002dfb81.

這裡注意,把ptr2輸出來的時候就要考慮大小端模式了,我的環境為小端模式,所以位址的低位儲存的是資料的高位。具體在記憶體中的儲存為如下情況

因ptr2指向的是int型別,所有把*ptr2輸出的時候它會連續取四個位元組。位址空間為0x002dfb81~0x002dfb84。該位址空間對應的資料為 00000000 00000000 00000000 00000010,把此資料用小端模式讀取出來為0x02000000。所以以16進製制輸出的結果2000000,0x02000000轉換為十進位制為33554432.

reference:

**:

大小端模式

偶 注意 大小端的高低位資料是按位址來計算的。如0x1001,10是高位位元組,01是低位位元組。char s abcd a是高位位元組 所謂的大端模式,是指資料的低位 就是權值較小的後面那幾位 儲存在記憶體的高位址中,而資料的高位,儲存在記憶體的低位址中,這樣的儲存模式有點兒類似於把資料當作字串順...

大小端模式

所謂的大端模式,是指資料的低位 就是權值較小的後面那幾位 儲存在記憶體的高位址中,而資料的高位,儲存在記憶體的低位址中,這樣的儲存模式有點兒類似於把資料當作字串順序處理 位址由小向大增加,而資料從高位往低位放 所謂的小端模式,是指資料的低位儲存在記憶體的低位址中,而數 據的高位儲存在記憶體的高位址中...

大小端模式

端模式 endian 的這個詞出自jonathanswift書寫的 格列佛遊記 這本書根據將雞蛋敲開的方法不同將所有的人分為兩類,從圓頭開始將雞蛋敲開的人被歸為bigendian,從尖頭開始將雞蛋敲開的人被歸為littileendian。小人國的內戰就源於吃雞蛋時是究竟從大頭 big endian ...