国产精品免费无遮挡无码永久视频-国产高潮视频在线观看-精品久久国产字幕高潮-国产精品99精品无码视亚

查看: 3543|回復: 0
打印 上一主題 下一主題

打雞蛋你從大頭打破還是從小頭打破?嵌入式C語言之大小端模式、字節序

[復制鏈接]
跳轉到指定樓層
樓主
發表于 2017-6-13 09:50:48 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
關鍵詞: C語言

大、小端模式的說法,來自喬納森·斯威夫特的小說《格列夫游記》,在小人國內部分裂成 Big-endian 和 Little-endian 兩派,他們的爭論在于一派要求從雞蛋的大頭把雞蛋打破,另一派要求從雞蛋的小頭把雞蛋打破。斯威夫特借以諷刺英國的政黨之爭,而計算機工業則借此表示數據儲存順序的分歧。


大端模式,是指數據的高字節保存在內存的低地址中,而數據的低字節保存在內存的高地址中,這樣的存儲模式有點兒類似于把數據當作字符串順序處理:地址由小向大增加,而數據從高位往低位放;這和我們的閱讀習慣一致。

記憶方法: 地址的增長順序與值的增長順序相反。

小端模式,是指數據的高字節保存在內存的高地址中,而數據的低字節保存在內存的低地址中,這種存儲模式將地址的高低和數據位權有效地結合起來,高地址部分權值高,低地址部分權值低,和我們的邏輯方法一致。

記憶方法: 地址的增長順序與值的增長順序相同。


那么,為什么會有大小端模式之分呢?

這是因為在計算機系統中,我們是以字節為單位的,每個地址單元都對應著一個字節,一個字節為 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則為大端模式。很多的ARMDSP都為小端模式。有些ARM處理器還可以隨時在程序中(在ARM Cortex 系列使用REV、REV16、REVSH指令)進行大小端的切換。

如此說來,大小端模式就是處理器在內存中對多字節數據進行存取的不同方式。注意兩點:一是處理器,大小端模式是處理器的差異造成的;二是多字節數據,也就是說只有處理器操作的數據類型超過一個字節時才會存在大小端模式的問題,而操作char類型數據是不存在該問題的。
  
字節序是指多字節數據在計算機內存中存儲或者網絡傳輸時各字節的存儲順序。字節序與大小端模式的概念相似,我們上面所說的就是在計算機內存中存儲的字節順序問題(即主機字節序),此外還存在網絡傳輸中的字節順序問題(即網絡字節序)。
  
那么,為什么會存在網絡字節序呢?


我們知道,網絡傳輸上的數據流是字節流,對于一個多字節數值,在進行網絡傳輸的時候,就需要考慮先傳遞哪個字節?也就是說,當接收端收到第一個字節的時候,它是將這個字節作為高位還是低位來處理呢?實際上,接收端收到的第一個字節會被當作高位看待,這就要求發送端發送的第一個字節應當是高位。而在發送端發送數據時,發送的第一個字節是該數字在內存中起始地址對應的字節。可見多字節數值在發送前,在內存中數值應該以大端模式存放。


網絡字節序是 TCP/IP 中規定好的一種數據表示格式,它與具體的 CPU 類型、操作系統等無關,從而可以保證數據在不同主機之間傳輸時能夠被正確解釋。好了,我們需要記住,網絡字節序是一種規定,它采用的是大端模式(Big-endian)。
  
在網絡程序開發或是跨平臺開發時,就需要注意字節序的問題了。應該保證只用一種字節序,否則兩方的解釋不一樣就會產生錯誤。為了方便開發,BSD socket 提供了以下四個轉換函數:


htons 把 unsigned short 類型從主機序轉換到網絡序
htonl 把 unsigned long 類型從主機序轉換到網絡序
ntohs 把 unsigned short 類型從網絡序轉換到主機序
ntohl 把 unsigned long 類型從網絡序轉換到主機序
在使用 Little-endian 的系統中,這些函數會把字節序進行轉換;而在使用 Big-endian 的系統中,這些函數會定義成空宏。

看到這里,就會想:為什么只有 short 和 long 類型?對于 float 和 double類型怎么處理?要是遇到64位系統怎么辦?

有網友說:htons 和 htonl 是因為 TCP/IP 的一些參數用到 int 和 long,但沒有 float 和 double 的參數。另外,float 和 double,與 CPU 無關。一般編譯器是按照 IEEE 標準解釋的,即把 float/double 看作4/8個字符的數組進行解釋。因此,只要編譯器是支持IEEE浮點標準的,就不需要考慮字節順序。

大家注意到,這里說不需要轉換,也是有條件的。我沒有考證過例外情況的存在比例,但是我相信在絕大部分情況下,編譯器都是符合IEEE標準的。如果你實在不放心,可以采取下面兩種辦法:

(1) 在保證不超過int范圍的情況下,將浮點數乘以100(或1000,10000,視所需精度隨你定)轉換為整數傳輸,在接收端再除以100,得到浮點數。


此外,我們還會聽到 Java字節序,Java字節序與網絡字節序一樣,采用大端模式。不是說大小端模式只跟 CPU 有關嗎?也就是說不同的計算機系統采用不同的字節序存儲數據,一種 CPU 不是 Big-endian 就是Little-endian。那這個 Java字節序到底是什么鬼?


Java 程序員是幸福,因為相對于 C/C++ 的不跨平臺,JVM 為開發人員屏蔽了大量的底層細節和復雜性,從而能夠將精力放在實現特定的業務邏輯上,因此 JVM 規定了數據的存儲順序(即大端模式)。所以做 Java 程序開發完全可以忽略字節序的存在,甚至有些 Java 程序員根本沒聽過字節序的概念。

以下課程可免費試聽C語言、電子PCBSTM32LinuxFPGA、JAVA、安卓等。
想學習的你和我聯系預約就可以免費聽課了。
宋工企鵝號:3524-6590-88   Tel/WX:173--1795--1908




您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表