一、字節序,為字節的順序,就是大於一個字節類型的數據在內測中的存放循序,一個字節的數據
當然就沒有順序可言了。
二、大端序與小端序
字節序分為兩類:Big-Endian 和 Little-Endian。
1、Little-Endian(小端序)就是低位字節排放在內存的低地址端,高位字節排放在內存的高地址端。
2、Big-Endian(大端序)就是高位字節排放在內存的低地址端,低位字節排放在內存的高地址端。
unsigned int整形數據0X12345678為例,其大端序、小端序的存儲內容如圖所示:
如0X01000000就為內存的低地址端,0x01000003就為內存的高地址端
而數據0x12345678左邊為高位字節,右邊的為低位字節,也就是說0x12位高位字節,
0x78為低位字節
unsigned int i= 0x12345678; unsigned char* p = (unsigned char*)&i; printf("%x\n", p[0]); //打印出16進制的78 printf("%x\n", p[3]); //打印出16進制的12
如代碼所示,對i的地址進行類型轉換,指針p指向的是i在內存中的低地址端的位置,又因為這台店內內
存中存儲數據是以小端序類存儲的,所以內存辭職端存的是低位字節,所以怕p[0]以16進制來打印,打印
出78,p[3]打印出12。在一個數組中arr[4]中,arr[0]是低地址端,arr[3]是高地址端。
三、網絡字節序:4個字節的32 bit值以下面的次序傳輸:首先是0~7bit,其次是8~15bit,然后是16~23 bit,
最后是24~31 bit,這種傳輸次序稱作大端序字節,友誼TCP/IP首部中所有的二進制整數在網絡中傳輸是都要
以這種次序,因此他又稱作網絡字節序,比如,以太網頭部中2字節的“一台網幀類型”,標識后面數據的類型。
UDP/TCP/IP協議規定:把接收到的的第一個字節當做高位字節來看待,這就要求發送端發送的第一個字節是
高位字節;而在發送端發送數據時,發送的第一個字節是該數值在內存中起始地址(低地址)對應的那個字節,
也就是說,該數值在內存中的起始地址處對應的那個字節就是要發送的第一個高位字節(即:高位字節存放在
低地址處);
由此可見,多字節數值在發送之前,在內存中應該是以大端序存放的;所以說,網絡字節序是大端字節序;比
如我們經過網絡發送整形數值0x12345678時,在80X86平台中,它是以小端序存放的,在發送之前需要使用系
統提供的字節轉換函數htonl()將其轉換成為大端序存放的數值。對於ARP請求或應答的一台網幀類型來說,在
網絡傳輸時,發送的順序是0x08,0x06。
四、內存空間中的相關布局
關於內存空間布局情況的說明:
| 棧底
.
. 棧
.
棧頂
-----------------------
|
|
\|/
|
|
-----------------------
堆
-----------------------
未初始化的數據
----------------(統稱數據段)
初始化的數據
-----------------------
正文段(代碼段)
----------------------- 最低內存地址 0x00000000
棧底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低地址)
以unsigned int value = 0x12345678為例,分別看看在兩種字節序下其存儲情況,我們可以用unsigned char buf[4]來表示value:Big-Endian: 低地址存放高位,如下圖:
棧底 (高地址)
---------------
buf[3] (0x78) -- 低位字節
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位字節
---------------
棧頂 (低地址)
棧底 (高地址)
---------------
buf[3] (0x12) -- 高位字節
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位字節
---------------
棧頂 (低地址)
————————————————
版權聲明:本文為CSDN博主「寂寂寂寂寂蝶丶」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/SwordArcher/article/details/82417429
1 bool isLittleEndian() 2 { 3 unsigned int i = 0x12345678; 4 unsigned char* c = (unsigned char*)&i; 5 return(*c == 0x78); //判斷是否是低位字節存內存低地址 *c取得就是內存中存放i的低地址 6 }
(2)通過聯合體判斷(返回真則為小端序,返回假則為大端序)
1 bool isLittleEndian() 2 3 { 4 union 5 6 { 7 int i; 8 9 char c; 10 11 }udata; 12 udata.i = 1; 13 14 return(udata.c == 1); 15 }
(3)linux環境下,通過htonl等函數直接判斷
1 #include <arpa/inet.h> 2 3 bool isLittleEndian() 4 5 { 6 7 return (1 != htonl(1)); 8 9 }
七、大小端的轉換
//短整型大小端互換#define BigLittleSwap16(A) ((((uint16_t)(A) & 0xff00) >> 8 ) | \\ (((uint16_t)(A) & 0x00ff) << 8 )) //長整型大小端互換#define BigLittleSwap32(A) ( (((uint32_t)(A) & 0xff000000) >> 24) | \\ (((uint32_t)(A) & 0x00ff0000) >> 8 ) | \\
(((uint32_t)(A) & 0x0000ff00) << 8 ) | \\ (((uint32_t)(A) & 0x000000ff) << 24))
結合判斷大小端的函數,如果本機是大端,則可以直接返回,如果本機是小端,則需要進行字節序的
轉換,或者進行網絡數據的轉換,在返回
uint16_t htons(uint16_t hostshort);//16位的主機字節序轉換到網絡字節序
uint32_t ntohl(uint32_t netlong);//32位的網絡字節序轉換到主機字節序
uint16_t ntohs(uint16_t netshort);//16位的網絡字節序轉換到主機字節序
————————————————
版權聲明:本文為CSDN博主「寂寂寂寂寂蝶丶」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/SwordArcher/article/details/82417429