字節序、大端序與小端序及其相關轉換


一、字節序,為字節的順序,就是大於一個字節類型的數據在內測中的存放循序,一個字節的數據

當然就沒有順序可言了。

二、大端序與小端序

字節序分為兩類: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。

四、內存空間中的相關布局

關於內存空間布局情況的說明:

----------------------- 最高內存地址 0xffffffff
 | 棧底
 .
 .              棧
 .
  棧頂
-----------------------
 |
 |
\|/
NULL (空洞)
/|\
 |
 |
-----------------------
                堆
-----------------------
未初始化的數據
----------------(統稱數據段)
初始化的數據
-----------------------
正文段(代碼段)
----------------------- 最低內存地址 0x00000000
以上圖為例如果我們在棧上分配一個unsigned char buf[4],那么這個數組變量在棧上是如何布局的呢?看下圖:
棧底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低地址)
現在我們弄清了高低地址,接着來弄清高/低字節,如果我們有一個32位無符號整型0x12345678,那么高位是什么,低位又是什么呢?其實很簡單。在十進制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進制也是如此。就拿 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。
 
五、網絡通訊字節的轉換
相同字節序的平台在進行我那個羅通信是可以不進行字節順序轉換,但是跨平台進行網絡數據通信時
必須進行字節序轉換。
原因如下:網絡協議規定接收到得第一個字節是高字節,存放到低地址,所以發送時會首先去低地址取數據的高字節。小端模式的多字節數據在存放時,低地址存放的是低字節,而被發送方網絡協議函數發送時會首先去低地址取數據(想要取高字節,真正取得是低字節),接收方網絡協議函數接收時會將接收到的第一個字節存放到低地址(想要接收高字節,真正接收的是低字節),所以最后雙方都正確的收發了數據。而相同平台進行通信時,如果雙方都進行轉換最后雖然能夠正確收發數據,但是所做的轉換是沒有意義的,造成資源的浪費。而不同平台進行通信時必須進行轉換,不轉換會造成錯誤的收發數據,字節序轉換函數會根據當前平台的存儲模式做出相應正確的轉換。
 
六、大小斷續的判斷
(1)通過指針判斷(返回真則為小斷續,返回假則為大端序)

————————————————
版權聲明:本文為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))

結合判斷大小端的函數,如果本機是大端,則可以直接返回,如果本機是小端,則需要進行字節序的

轉換,或者進行網絡數據的轉換,在返回

 

(2)winsock.h頭文件中的函數
uint32_t htonl(uint32_t hostlong);//32位的主機字節序轉換到網絡字節序
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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM