<strike id="xh1ss"><address id="xh1ss"></address></strike>
  1. <legend id="xh1ss"></legend>
  2. 更多課程 選擇中心

    嵌入式培訓
    達內IT學院

    400-111-8989

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

    • 發布:嵌入式培訓
    • 來源:嵌入式問答
    • 時間:2017-09-18 13:39

    很多人討厭碰到字節序問題,跟它打交道就像走迷宮,每次都要犧牲不少腦細胞。即使這一次似乎搞清楚了,下次碰到還是要重新在大腦里構建和模擬。這里盡量做一個字節序問的完整備忘記錄。

    1.主機字節序

    多字節數據在內存中的字節排列順序稱為主機字節序,主機字節序基本由CPU硬件決定,某些CPU如X86、Z80等為little-endian;有些如moto6800、sparc等為big-endian;而有些CPU可通過寄存器設置支持不同字節序,如ARM、MIPS等,這類平臺上不同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寄存器,這中間沒有額外字節序轉換的硬件開銷,只是不同總線連接方式導致了不同字節序。

    2.信息交換中的字節序

    當不同類型平臺通過某種媒介交換信息時需要考慮字節序問題,常見介質主要指文件和網絡。通過文件或網絡讀取來自其它主機的多字節數據時,要警惕字節序問題。如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);

    }

    3.想想指針怎么做?

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

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

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

    4.補充SOC內部的字節序

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

    總結

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

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

    預約申請免費試聽課

    填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

    上一篇:大學生適合參加嵌入式培訓嗎?
    下一篇:現在嵌入式培訓學校哪家強呢?

    怎么樣成為優秀嵌入式系統開發工程師?

    想學嵌入式開發,嫌自學時間長怎么辦?

    嵌入式開發工程師怎么樣?

    嵌入式開發學習難不難?

    • 掃碼領取資料

      回復關鍵字:視頻資料

      免費領取 達內課程視頻學習資料

    • 視頻學習QQ群

      添加QQ群:1143617948

      免費領取達內課程視頻學習資料

    Copyright ? 2021 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

    選擇城市和中心
    黑龍江省

    吉林省

    河北省

    湖南省

    貴州省

    云南省

    廣西省

    海南省

    黄色一级全祼,欧美一级aa片,一级毛卡片,一级特黄大片,三级片视频 百度 好搜 搜狗
    <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>