關于大小端存儲的問題,在嵌入式開發里這個早已不是什么新鮮事兒了。作為開發者都有著很清晰的認識,在此就嵌入式開發中的大小端問題,做個簡單的分享總結。
大端小端,是相對內存而言的。有關大小端的資料,互聯網上一搜就一大堆的博文和百科知識點,這里就不再贅述。
在工程項目中,需要處理大小端差異的,主要出現在數據處理的過程中,常見的有:
1.數據包解析和組包
2.數據收發和參數傳遞
數據包解析和組包
數據包解析和組包的過程,可以參考《嵌入式硬件通信接口協議-UART(四)設計起止式的應用層協議》該文中的“設計協議幀結構”部分,該部分內容講到把uint16_t字段的數據使用2個uint8_t類型的數據表示,旨在數據傳輸時沒有差異。
但是,有些接口是別人設計好的,作為應用者你只能“順從”地使用。
在C語言里可以利用強制轉換來實現對數據類型的轉換,但是強轉的結果依賴于當前平臺大、小端情況的。
如下的類型強制轉換,將uint8_t類型buf中的數據流強制轉為uint16_t類型后取出賦值給tmp_dat變量,根據觀察發現buf中的數據流被每2個字節“組合”成一個uint16_t類型的數據,Debug過程截圖如下:


代碼中的p1是一個uint16_t類型指針,指向uint8_t類型數據流的tmp_stream,此處的指針賦值就需要使用強制轉換。
在for循環內以p1指針為“起點”循環做偏移取出數據,并且每次偏移uint16_t類型的數據寬度,因為p1是uint16_t類型指針。
觀察取出數據存放的tmp_dat變量,可見數據被從左到右(也就是從低地址到高地址)每2個字節“組合”成uint16_t類型,比如0x11和0x12組合成0x1122,0x33和0x44組合成0x3344......可見,低地址的那一個數據組合后成為了uint16_t的高字節部分!這就是大端模式!
同樣的代碼,拿到小端模式的ARM平臺里運行,結果就完全不一樣了:


不難發現,在小端平臺里,數據被從左到右(也就是從低地址到高地址)每2個字節“組合”成uint16_t類型了,而此時0x11和0x12組合成0x2211,同時0x33和0x44組合成0x4433……可見,低地址的那一個數據組合后成為了uint16_t的低字節部分!這就是小端模式!
類似的問題,也會出現在強制轉換為結構體的過程中,并且實際得到的結構體由于大小端問題,部分成員已經“變了樣”!
使用同一數據流,利用一結構體指針p2指向該數據流進行解析,對比不同平臺強制轉換后的結構體部分成員的情況。