单片机(MCU)如何才能不死机之对齐访问(Aligned Access)
從一個結構體說起。如下,在 STM32F0 的程序中,我們定義了一個結構體My_Struct ,那么這個結構體占用多少內存呢?
struct?Struct_Def?{ uint8_t?Var_B; uint16_t?Var_W0; uint16_t?Var_W1; uint32_t?Var_DW; }; struct?Struct_Def?My_Struct; int?main(void) {??My_Struct.Var_B?=?0x01;??My_Struct.Var_W0?=?0x0203;??My_Struct.Var_W1?=?0x0405;??My_Struct.Var_DW?=?0x06070809;????while(1); }我們粗略一算,1 + 2 + 2 + 4 = 9 Bytes 。
下載到芯片,觀察一下變量,似乎沒錯。
圖片如果有更進一步的好奇心,我們來到內存中實際看一下,可能會有出乎意料的發現:
圖片編譯器在 Var_B 之后插入了一個字節,在 Var_W1 之后插入了兩個字節。這個結構體在內存中實際占用了 1 + 1 + 2 + 2 + 2 + 4 = 12 Bytes 。
為什么會這樣呢?這是 ARM Cortex M0 體系決定的,它只支持對齊訪問 ( Aligned Access )。比如我們訪問一個 4 字節 (Double Word) 型的變量時,如果這個變量的起始地址是能被 4 整除的話,我們說這種訪問是雙字節對齊的。如果訪問一個 2 字節 ( Word ) 變量,當起始地址能被 2 整除時是對齊的。訪問字節 ( Byte ) 型變量,總是對齊的。
那么如果進行了非對齊訪問呢?那就會產生一個嚴重錯誤 ( HardFault ) !!!
大家看一下例子中的這一個賦值語句:
My_Struct.Var_DW = 0x06070809;
它是一個 4 字節 ( Double Word ) 型的變量賦值。Var_DW 這個成員,如果按照在結構體中的順序,應該緊隨 Var_W1 之后,分配在 0x20000012,但是這個地址是不能被 4 整除的,所以編譯器在填充了 2 個字節 0 之后,把 Var_DW 的起始地址分配在了 0x20000014 。
圖片到這里大家肯定會有一個疑問,這樣豈不是很浪費 RAM 嗎?RAM 又是相對來說價格比較高的。特別是在結構體比較多的情況下,大量的 RAM 白白浪費了!
還好,在這里我們可以用到偽指令 #pragma pack 了。
如下例所示,#pragma pack(1) 將會使結構體中的變量一個字節緊挨著一個字節在內存中分配,而不再考慮是否對齊的問題。可以看到結構體占用從 0x2000000C 到 0x20000014 的9個字節 RAM空間。
#pragma?pack(1) struct?Struct_Def? {uint8_t?Var_B;uint16_t?Var_W0;uint16_t?Var_W1;uint32_t?Var_DW; }; struct?Struct_Def?My_Struct; #pragma?pack()那么問題來了,當我們讀寫地址非對齊的變量時,不就會產生 HardFault 嗎?
在這里,編譯器采取了曲線救國的方針。大家看下面賦值語句對應的匯編部分就會看到,它用 4 個STRB 指令(單字節操作,無論任何地址都是對齊操作), 代替了 1 個 STR 指令 ( 4 字節操作 )。如此,犧牲了一些效率,但是節省了內存空間。
圖片這種用法節省了 RAM,但是帶來了一種比較隱蔽的錯誤。尤其是當我們用指針方式訪問這些變量時,編譯器無法發現錯誤,而且只有當語句實際執行時才會引起問題。所以在使用指針式要特別注意,指針所指向的地址,是否和指針類型所需要的地址對齊方式吻合。
以上面的 RAM 分配方式為例,非對齊訪問時會導致 MCU 進入 HardFault 。
volatile?uint32_t?Test_Var; Test_Var?=?*(uint8_t?*)(&My_Struct.Var_B);?//?這句是可以正確執行的Test_Var?=?*(uint16_t?*)(&My_Struct.Var_W0);?//?非對齊訪問,進入?HardFaultTest_Var?=?*(uint32_t?*)(&My_Struct.Var_DW);?//?非對齊訪問,進入?HardFault對于變量的定義,我們還可以用下面的偽指令把變量以 n 字節對齊:
__align(n)
大家在實際工程中可以根據實際情況靈活的選擇和使用這些偽指令。
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識小密圈
關注公眾號,后臺回復「1024」獲取學習資料網盤鏈接。
歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~
總結
以上是生活随笔為你收集整理的单片机(MCU)如何才能不死机之对齐访问(Aligned Access)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: void 型指针的高阶用法,你掌握了吗?
- 下一篇: 基础搜索(kuangbin专题)