位元組序(Endianness) 大端和小端

2021-10-04 02:57:14 字數 3776 閱讀 7706

寫在前面:

位元組序,也就是位元組的順序,指的是多位元組的資料在記憶體中的存放順序;在記憶體中,資料是以位元組(8bit)儲存的,當儲存 16bit或者 32bit時,就面臨著大端 (big-endian)儲存, 還是小端 (little-endian) 儲存的問題。

先來講乙個故事:從前,有乙個國王的兒子,在吃雞蛋的時候,被蛋殼割破了手指;之所以發生這種情況是因為這個國家有乙個傳統,那就是在吃雞蛋前從雞蛋的較大一端開始打破。因為這次事件,國王非常焦慮,決定禁止所有臣民在雞蛋較大的一端敲蛋;但是該政權的反對者躲了起來,他們想要保持傳統,繼續從較大的一邊開啟雞蛋;為了這一區區爭端,導致了小人國的內戰,甚至殃及鄰國,於是此舉也使得這兩個島嶼爆發了一場關於雞蛋的血腥戰爭… ——《格列佛遊記

當然了,實際上並不是這樣的,其實是因為 ibm、intel等大公司不願合作,自搞自的,而且當時也沒有發布固定的標準,所以就一直沿用,才導致有大小端之分;說到底還是歷史遺留問題。

然後就牽涉出兩大 cpu派系:

因此,位元組序只和處理器架構有關

雞蛋有兩個末端,乙個較窄的末端(小端)和乙個較寬的末端(大端)

1、大端(big-endian)

位址增長方向 →

...0x0a0x0b0x0c0x0d...

位址增長方向 →

...0x0a0b0x0c0d...

最高的16bit單元0x0a0b儲存在低位。

2、小端(little-endian)

位址增長方向 →

...0x0d0x0c0x0b0x0a...

最低位位元組是0x0d儲存在最低的記憶體位址處。後面位元組依次存在後面的位址處。

位址增長方向 →

...0x0c0d0x0a0b...

最低的16bit單元0x0c0d儲存在低位。

← 位址增長方向

...0x0a0x0b0x0c0x0d...

最低有效位(lsb)是0x0d儲存在最低的記憶體位址處。後面位元組依次存在後面的位址處。

← 位址增長方向

...0x0a0b0x0c0d...

最低的16bit單元0x0c0d儲存在低位。

若是你還理解不了或者記不住他們所對應的關係,可以看下圖:

如果你寫的程式只在單機環境下面執行,而不需要與別人互動,那麼你完全可以忽略位元組序的存在;若是存在互動,那麼就得注意了

eg:1、在 arm核心的 stm32f4xx中:

2、在 c8051核心的 51微控制器裡:

根據上面所說的,因為這兩款微控制器的位元組序(也就是他們儲存的方式)不一樣,若是實現通訊互動,那麼,他們彼此得到的資料將會出現顛倒現象;試想,如果 stm32f4xx微控制器將變數a = 0x12345678的首位址傳遞給了 51微控制器,由於 51微控制器採取 big endian 方式儲存資料,若是不做處理,那麼很自然的它會將你的資料翻譯為0x78563412。顯然,問題就出現了!!!

/* 

原理:聯合體 union的存放順序是所有成員都從低位址

開始存放,而且所有成員共享儲存空間

*/void endianness(void)

temp;

temp.a = 0x1234;

if( temp.b == 0x12 )//低位元組存的是資料的高位元組資料

else

}

小端序(先傳低位)的序列協議大端序(先傳高位)的序列協議

#define reversebytes_uint16(a)		((a & 0x00ffu) << 8 | (a & 0xff00u) >> 8)

#define reversebytes_uint32(a) (a & 0x000000ffu) << 24 | (a & 0x0000ff00u) << 8 \

| (a & 0x00ff0000u) >> 8 | (a & 0xff000000u) >> 24)

猜一下以下程式輸出什麼:

// 假設硬體平台是intel x86(little endian)

typedef

unsigned

int uint32_t;

#define uc(b) (((int)b)&0xff)

//byte轉換為無符號int型

void

inet_ntoa

(uint32_t in)

intmain

(void

)

先來看以下的函式:

int

main

(void

)

按照小字節序的規則,變數a在計算機中儲存方式為:

高位址方向

0x12

0x34

0x56

0x78

低位址方向

p[3]

p[2]

p[1]

p[0]

注意,p並不是指向 0x12345678的開頭 0x12,而是指向 0x78。p[0]到 p[1]的操作是 &p[0]+1,因此 p[1]位址比 p[0]位址大。輸出結果為 120.86.52.18。

反過來的話,令 int a = 0x87654321,則輸出結果為 33.67.101.-121。

為什麼有負值呢?因為系統預設的 char是有符號的,本來是 0x87也就是 135,大於 127因此就減去 256得到 -121。

那麼,最後結果為:120.86.52.18和 33.67.101.135

參考:

位元組序問題 Endianness

特別強調 只有多位元組物件才會有多位元組問題,單位元組物件是不存在這個問題的多位元組物件 比如int 一般為4個位元組 float,short 一般兩個位元組 等 多位元組物件就不同了,因為他有多個位元組,然後順序的問題就出現了,就像排列組合一樣,多個元素排列方法多種多樣 位元組序只用到兩種特殊的排...

大端位元組序 小端位元組序

大端位元組序 大端儲存模式是指資料的低位元組內容儲存到記憶體的高位址中,而資料的高位元組內容儲存到記憶體的低位址中 小端位元組序 小端儲存模式是指資料的低位元組內容儲存到記憶體的低位址中,而資料的高位元組內容儲存到記憶體的高位址中 程式驗證 include int main return 0 程式改...

大端位元組序 小端位元組序(網路位元組序 主機位元組序)

大端位元組序 整數的高位位元組儲存在記憶體的低位址處,低位元組儲存在記憶體的高位址處。一般pc大多採用小端位元組序,也稱為主機位元組序。網路上傳輸採用大端位元組序,也稱為網路位元組序。linux中常用轉換函式如下 include uint32 t htonl uint32 t hostlong 無符...