成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我們一起聊聊如何理解字節序

開發 前端
字節序是計算機存儲多字節數據的方式,目前的方式有:大端字節序和小端字節序,字節序主要是針對多字節的數據類型,比如 short、int 等。

 [[439739]]

計算機只能理解 0 和 1 組成的二進制數據, 一個 bit 的值是 0 或 1,八個這樣的 bit 組成了一個字節,通過字節,計算機可以表示一些復雜的數據,比如:音頻、視頻等,有些數據用一個字節就能表示,比如英文字符,而有些數據需要多個字節來表示,比如:漢字, 對于多字節的數據,存儲的時候會有字節順序的問題,也就是字節序

字節序是什么

字節序是計算機存儲多字節數據的方式,目前的方式有:大端字節序和小端字節序,字節序主要是針對多字節的數據類型,比如 short、int 等

  • 大端字節序

高位字節存儲在內存的低地址上,低位字節存儲在內存的高位地址上

  • 小端字節序

高位字節存儲在內存的高地址上,低位字節存儲在內存的低地址上

如何理解字節序

我們平常書寫和閱讀數字的習慣是從左到右的,所以把最左邊的字節當作最高位字節,最右邊的字節當作做最低位字節,從左到右,表示從高位字節到低位字節

例如:對于 0x01020304,它的大端和小端字節序在內存中的布局如下圖所示

0x 01 02 03 04 總共四個字節大小,以人們習慣的閱讀順序,0x01 處于左邊,屬于高位字節,0x04 處于右邊,屬于低位字節

內存地址從 0x 00 00 00 07 到 0x 00 00 00 0A 4個字節的空間,剛好能存儲得下

根據大端字節序的的規則:高位字節存儲在內存低地址,所以處于高位字節的 0x01 存儲在 0x 00 00 00 07 地址處,緊接著 次高位字節 0x02 存儲在次低地址 0x 00 00 00 08 處,剩下的兩個字節 0x03 和 0x04 分別存儲于 0x 00 00 00 09 和 0x 00 00 00 0A 地址處,最后的結果是 0x 01 02 03 04

小端字節序和大端剛好相反,它指的是 高位字節存儲在內存高地址處,所以處于高位字節的 0x01 存儲在 0x 00 00 00 0A 地址處,次高位字節 0x02 存儲在次高地址 0x 00 00 00 09 處,余下的 0x03 和 0x04 分別存儲于 0x 00 00 00 08 和 0x 00 00 00 07 地址處,最后的結果是 0x 04 03 02 01

從上圖可以看出,對于相同的數據,大端和小端的內存布局是不一樣的,大端字節序的存儲形式更符合人們平常書寫和閱讀的習慣

為什么會有字節序

可能有人會感到疑惑:既然大端字節序更符合人們閱讀的習慣,為什么不全部都采用大端的方式,這樣也就不會有字節序的問題了 ?

確實,如果所有平臺都用同一種存儲順序,就沒有字節序這一說法了

在早期, CPU 只有幾千個邏輯門,小端的方式能更有效的使用邏輯電路,所以很多計算機內部計算都采用小端的方式,這種方式也就保留到了現在

另外,字節序是跟 CPU 架構相關,不同的廠家設計的規范可能都不一樣,比如 Intel 的 x86 是小端方式,而 IBM 的 PowerPC 則采用大端方

大端的方式更符合人們的閱讀習慣,因此大部分網絡傳輸以及文件存儲都是大端的方式

總的來說,小端主要是在計算機內部使用,大端則在外部使用

計算機如何處理字節序

計算機讀取數據的時候是不區分字節序的,它總是從內存低地址到高地址的順序,按字節讀取

下面的示例圖展示了數據 0x0102 的 大端和小端的內存布局以及CPU讀取內存的順序

由上圖可知,對于大端字節序來說,內存低地址處存儲的是高位字節,也即計算機讀取內存的第一個字節就是高位字節,小端字節序就正好相反,內存低地址處存儲的是低位字節,讀取內存的第一個字節是低位字節

計算機只有在讀取數據的時候才需要區分字節序

就拿上面展示大端方式的圖 ( 第一張 ) 來說,內存 0x 00 00 00 07 地址處存儲的數據是 0x01 , 0x 00 00 00 08 地址處存儲的數據是 0x02

如果是以大端的方式讀取的話,地址 0x 00 00 00 07 處的數據 0x01 會放到高位字節, 0x 00 00 00 08 處的數據是 0x02 放到低位字節,最終這兩個字節的數據是 0x 01 02

如果是以小端的方式讀取的話,,地址 0x 00 00 00 07 處的數據 0x01 會放到低位字節, 0x 00 00 00 08 處的數據是 0x02 放到高位字節,最終這兩個字節的數據是 0x 02 01

網絡字節序

所有的協議都是人類編制定的,大端對人們閱讀更友好,所以 IEEE 標準協會規定除非有明確說明,否則網絡協議都使用大端字節序, 像 TCP/IP 就是如此

還記得我們在編寫網絡程序的時候,傳入 connect 函數實參中的 端口號嗎, 傳入之前需調用 htons 函數將其轉成網絡字節序,也就是要轉成大端字節序,下面是部分代碼示例

  1. struct sockaddr_in addr; 
  2.  
  3. addr.sin_family = AF_INET; 
  4.  
  5. addr.sin_addr.s_addr = inet_addr("192.168.1.10"); 
  6.  
  7. addr.sin_port = htons( 5000 ); 
  8.  
  9. connect( clientfd, (struct sockaddr *)&addr, sizeof(addr)) ) 

上面紅色的 htons 函數的作用是將 端口號 由主機字節序轉成網絡字節序,網絡字節序大多時候都是固定為大端序的,但不同的機器,主機序卻不一樣,如果本身就已經是大端了,調用 htons 函數,返回值和實參是一樣的,如果本身是小端,結果會轉成大端的形式,具體的數值也會不一樣

怎么判斷大小端

上面提到了主機字節序,那如何知道當前機器是大端還是小端呢 ?

因為操作系統必須適配所有類型的 CPU ,所以對于操作系統來說,大端和小端它都是支持的

為了讓程序易于判斷當前平臺是大端還是小端,Linux 下 glibc 庫提供了下面幾個宏定義

  1. BIG_ENDIAN # 大端序 
  2.  
  3. LITTLE_ENDIAN # 小端序 
  4.  
  5. BYTE_ORDER # 字節序 

下面是測試代碼 test.c 文件

  1. #include <stdio.h> 
  2. int main(int argc, char *argv[]) 
  3.     if(BYTE_ORDER == BIG_ENDIAN) 
  4.     { 
  5.         printf("big endian...\n"); 
  6.     } 
  7.     else 
  8.     { 
  9.         printf("little endian...\n"); 
  10.     } 

執行 gcc -g -o test test.c 命令進行編譯,運行測試程序,結果如下:

  1. [root@localhost test]# ./test 
  2.  
  3. little endian... 

由此,可以知道當前平臺是小端字節序

除了用上面的方法之外,我們可以根據大端和小端的特點,自己寫代碼獲取,修改 test.c 文件,內容如下

  1. #include <stdio.h> 
  2. int main(int argc, char *argv[]) 
  3.     union 
  4.     { 
  5.         unsigned short i; 
  6.         char ch[2]; 
  7.     }un; 
  8.      
  9.     un.i = 0x0102; 
  10.     if(0x01 == un.ch[0]) 
  11.     { 
  12.          printf("big endian...\n"); 
  13.     } 
  14.     else 
  15.     { 
  16.          printf("little endian...\n"); 
  17.     } 

編譯并運行,結果如下:

  1. [root@localhost test]# ./test 
  2.  
  3. little endian... 

可以看出,不管是通過系統庫提供的宏來判斷還是自行封裝接口來判斷機器的字節序都是可行的

最后,如果想知道 LITTLE_ENDIAN、 BIG_ENDIAN 、BYTE_ORDER 宏定義的詳細情況,可以查看 glibc 源碼,它們在 glibc-2.17\string\endian.h 以及 glibc-2.17\sysdeps\x86\bits\endian.h 文件中

注意:不同版本的 glibc 源碼,具體的位置可能有差異,我使用的是 glibc-2.17 版本

大端小端的轉換

熟悉了大端和小端特點,它們之間的轉換就簡單了,對于兩字節來說,每個字節值不變,互換字節位置,如果是更多字節的話,最低位字節和最高位字節交換,次低位字節與次高位字節交換,直到所有字節都完成了一遍交換為止

比如:下面是小端轉大端的偽代碼

  1. #小端轉大端  假設:ch 和 i  是小端序 
  2.  
  3. char ch[2]; 
  4.  
  5. int i = 0; 
  6.  
  7. # x 是大端字節序 
  8. x = ch[1] << 8 | ch[0]  
  9.  
  10. # y 是大端字節序 
  11. y =   ( (i & 0xff000000) >> 24 ) |  ( (i & 0x00ff0000) >> 8 ) | ( (i & 0x0000ff00) << 8 )  | ( (i & 0x000000ff) << 24 ) 

變量 i 字節序轉換說明:按照從左到右的順序,把 i 的第一個字節右移 3 個字節( 24 bit ),第二個字節右移 1 字節 ( 8 bit ),第三個字節左移 1 字節 ( 8 bit ),第四個字節左移 3 個字節 ( 24 bit ),最后把移位后的字節組合起來就可以了

在實際的程序處理中,不應該出現字節序的問題,只有 "網絡字節序" 和 "主機字節序" ,需要轉換字節序時,使用 ntohl, ntohs, htonl, htons 等函數即可

  1. ntohl       # uint32 類型 網絡序轉主機序 
  2. htonl       # uint32 類型 主機序轉網絡序 
  3.  
  4. ntohs       # uint16 類型 網絡序轉主機序 
  5. htons       # uint16 類型 主機序轉網絡序 

小結

本文詳述了字節序的一些知識,開發網絡應用的時候會涉及到字節序的相關問題,所以,花點兒時間弄明白還是很有必要的

 

責任編輯:武曉燕 來源: Linux開發那些事兒
相關推薦

2024-02-20 21:34:16

循環GolangGo

2021-08-27 07:06:10

IOJava抽象

2023-08-10 08:28:46

網絡編程通信

2023-08-04 08:20:56

DockerfileDocker工具

2023-06-30 08:18:51

敏捷開發模式

2022-05-24 08:21:16

數據安全API

2023-09-10 21:42:31

2024-09-09 00:00:00

編寫技術文檔

2023-04-03 00:09:13

2024-09-30 09:33:31

2024-11-27 16:07:45

2021-10-26 09:55:52

CAP理論分布式

2022-10-28 07:27:17

Netty異步Future

2022-11-12 12:33:38

CSS預處理器Sass

2022-06-26 09:40:55

Django框架服務

2023-04-26 07:30:00

promptUI非結構化

2022-02-14 07:03:31

網站安全MFA

2025-03-27 02:00:00

SPIJava接口

2023-07-27 07:46:51

SAFe團隊測試

2022-01-04 12:08:46

設計接口
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲一一在线 | 久久久成人免费视频 | 精品成人免费一区二区在线播放 | 亚洲精品在线视频 | 日产精品久久久一区二区福利 | 日韩在线视频免费观看 | 欧美群妇大交群中文字幕 | 伊人网综合在线 | 亚洲精品久久久久国产 | 91玖玖| 一区二区三区在线免费观看 | 成人一区在线观看 | 日韩中文字幕在线不卡 | 狠狠操狠狠 | 天天射影院 | 色综合久久久 | 亚洲成人免费观看 | 麻豆av在线 | 国产a级毛片 | 嫩草伊人| 欧美日韩精品一区二区天天拍 | 国产成人精品一区二区三区网站观看 | 91不卡| 欧美激情在线一区二区三区 | 亚洲综合婷婷 | 人人做人人澡人人爽欧美 | 午夜在线| 一区二区日本 | 99视频在线| 午夜ww| 99久久精品免费看国产高清 | 北条麻妃av一区二区三区 | 欧美日韩福利 | 韩日av在线| 欧美亚洲视频在线观看 | 久久久性色精品国产免费观看 | 精品亚洲一区二区三区 | 午夜视频在线播放 | 久久久美女 | www.久久.com| 五月天天色 |