国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

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

嵌入式基礎知識硬件篇之字節序

[復制鏈接]
跳轉到指定樓層
樓主
發表于 2017-9-8 10:15:10 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
很多人討厭碰到字節序問題,跟它打交道就像走迷宮,每次都要犧牲不少腦細胞。即使這一次似乎搞清楚了,下次碰到還是要重新在大腦里構建和模擬。這里盡量做一個字節序問的完整備忘記錄。

主機字節序
多字節數據在內存中的字節排列順序稱為主機字節序,主機字節序基本由CPU硬件決定,某些CPU如X86、Z80等為little-endian;有些如moto6800、sparc等為big-endian;而有些CPU可通過寄存器設置支持不同字節序,如ARMMIPS等,這類平臺上不同OS可能配置了不同字節序。

理解字節序需要知道兩個名詞:MSB (Most Significant Byte),代表一個數中權值最大的字節;LSB(Least Significant Byte),代表一個數中權值最小的字節。比如十進制數1234,1權值為千位,最大,相當于MSB;4為個位,權值最小,相當于LSB。那么真正以字節為單位考慮, 4字節數0x12345678里那個是MSB/LSB呢?

主機字節序分Big-Endian和Little-Endian兩種,定義為:

a. Little-Endian,又稱低字節優先,是把LSB放在內存低地址端,MSB在內存高地址端。舉例,4字節數0x12345678在little-endian體系的內存中存放(從地址0x1000開始)為:

b. Big-Endian,又稱高字節優先,把MSB放在內存低地址端,LSB放在內存高地址端。0x12345678此時存放為:

big-endian沿地址增長方向先放高權位數字的方式恰好符合一般習慣(按照千,百,十,個位來書寫數字)。這也是為什么初學者變換endian時總覺得big-endian比較正常。

字節序問題有時會被擴大化,有人一碰到奇怪問題就懷疑字節序。其實它只存在于多字節數據在內存中的解析,注意:1)多字節數據;2)內存中的排列。

    a. 多字節數據是指諸如long int short等需要多個字節存儲的數據類型,而象char等用一個字節表示的類型永遠不會有字節序問題。

    b. CPU通用寄存器都是整體操作,不存在單字節地址以及地址增長方向的概念,因此也沒有MSB/LSB在前或在后的問題,只有內存中的多字節數據存儲才會有這兩種差異。從硬件角度看,CPU是直接通過數據總線連接內存和CPU寄存器,這中間沒有額外字節序轉換的硬件開銷,只是不同總線連接方式導致了不同字節序,如下圖(from wiki):

信息交換中的字節序
當不同類型平臺通過某種媒介交換信息時需要考慮字節序問題,常見介質主要指文件和網絡。通過文件或網絡讀取來自其它主機的多字節數據時,要警惕字節序問題。如x86和moto6800主機通過文件交換信息時,如果不轉換,數據處理就不匹配。在x86 VC下運行如下代碼:

  void main( )
    {
      FILE* fp;
      short a = 0x3132;   //為ASIIC碼’12’
      fp = fopen ("c:test.txt", "wb")
      fwrite(&a, sizeof(short), 1, fp);
      fclose(fp);
    }

代碼中a的值0x3132即'12’,由于x86為little endian體系,內存中多字節LSB(這里即0x32)在前,所以運行后打開test.txt文件,內容是'21'。把test.txt文件復制到moto6800機器上,再用fread把文件內容讀到short變量里,得到的就不是0x3132而是0x3231了,數據就此被顛倒,后續處理完全錯誤。

假設我們制定了介質層字節序標準(如big-endian),要通過軟件屏蔽不同endian體系的差異,需要兩步操作,一判斷endian類型:
typedef union {
      u16 a;
      u8 b[2];
    }ENDIAN;
    /* judge cpu is big endian(0) or small endian(1) */
    bool judge_endian(void)
    {
      ENDIAN t;
      t.a = 0x0001U;
      return (bool)(t.b[0] == 1);
    }

想想指針怎么做?

判斷完兩端主機的endian之后,要根據情況做相應endian交換,即發送和接收任何一方只要不符合媒介層標準(big-endian),就要通過移位和位操作,在主機序和媒介序之間轉換。一方發送數據前要先將內存數據由主機字節序轉換為傳輸介質層的字節序,再發送出去,接收方收到數據后,要轉換為本地的主機字節序,再做后續處理。

比如TCP/IP協議的socket通信,基于socket通訊的雙方一般選擇Big-Endian為標準,又稱網絡字節序。socket定義了一組轉換函數,用于多字節數在網絡字節序和主機字節序之間的轉換。htonl,htons用于主機序轉換到網絡序(如主機本身big endian,函數實際啥也不做);ntohl,ntohs把網絡序轉換到本機序(同樣)。因此傻瓜式做法,無論發送方主機字節序是什么,發送前都用htons或htonl將多字節數據轉換為網絡字節序;同樣無論接收方主機字節序是什么,都用ntohs或ntohl把接收的網絡數據轉換為本地主機字節序。這樣有了網絡字節序標準,socket通信時,只需套用這幾個函數就能方便地抹平主機間的字節序差異。

問題在于如果雙方主機都與網絡字節序相反,本來是可以直接通信的,卻用htonl/ntohl等轉過去又轉回來,有點自找麻煩。這就要看軟件的預期運行環境,以及怎樣平衡軟件效率和多平臺通用性。

補充SOC內部的字節序

soc中除主CPU外,一些外設中(如硬件媒體編解碼器)還包含內部MCU,它們之間一般通過高速總線共享外部DDR,通過低速總線共享外設寄存器。這時如果雙方的endian屬性不匹配,對host cpu驅動及MCU上的固件編寫會造成一定困擾。

總結

真正理解大小端的本質可能要從硬件系統角度,涉及CPU指令集、寄存器、總線以及硬件外設等。但對程序員來說,能夠了解字節序問題的存在范圍以及如何實現移植性更高的代碼,這就足夠了。

Tip:對于ARM等可配置的CPU,其編譯工具中會有big/little endian的選項,程序移植時也需要注意,如果跟系統設置不匹配,編譯得到的目標程序就無法運行。




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



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

本版積分規則

關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 91在线视频免费看 | 九九久久国产精品 | 美国免费黄色片 | 国产成人av在线 | 西野翔有码中文字幕在线 | 淫操干 | 91蜜桃传媒一二三区 | 一本大道香蕉大vr在线吗视频 | 国产亚洲精品成人久久网站 | 亚洲最大成人在线 | 亚洲丶国产丶欧美一区二区三区 | 黑人中文字幕在线精品视频站 | 麻豆精品免费视频入口 | 亚洲国产高清视频 | 中文字幕在线看日本大片 | 日韩一区二区超清视频 | 五月天婷婷色综合 | 99综合网 | 国产在线一区二区三区 | 99国产精品免费视频观看 | 啦啦啦免费观看 | 精品午夜久久福利大片免费 | 香蕉大黄香蕉在线观看 | 亚洲福利视频导航 | 国产区欧美 | 午夜网站在线观看免费网址免费 | 狠狠色噜噜狠狠狠狠97老肥女 | 国产区欧美 | 亚洲欧美不卡 | 一集毛片| 日本亚洲欧美在线 | 国产精品成人免费 | h免费观看 | 九九99视频在线观看视频观看 | 欧美日韩乱国产 | 欧美久久网 | 久久久久国产成人精品亚洲午夜 | 99久久免费精品国产免费高清 | 国产沙发系列69 | 久热操 | 国产福利免费看 |