前言
指針,是C語言中的一個重要概念及其特點,也是掌握C語言比較困難的部分。指針也就是內存地址,指針變量是用來存放內存地址的變量。
本質還是一個變量,指針提供了一種對存儲位置的動態(tài)訪問手段,(相對于普通變量而言,普通變量只能訪問自己所占的存儲位置)
內存地址對齊,是計算機在內存中的數(shù)據(jù)排列、訪問數(shù)據(jù)的方式,包含了基本數(shù)據(jù)對齊和結構體數(shù)據(jù)對齊的兩種相互獨立又相互關聯(lián)的部分。
現(xiàn)代計算機在內存中讀寫數(shù)據(jù)是按字節(jié)塊進行操作,理論上任意類型的變量訪問可以從任何地址開始,但是計算機系統(tǒng)對任意數(shù)據(jù)類型在內存中存放位置有限,它會要求這些數(shù)據(jù)的首地址的值為K(4位或者8位)的整數(shù)倍。
如何踩坑的?
在一份十分優(yōu)秀的代碼中,指針的使用率占比很高,因為指針能讓代碼實現(xiàn)變得更自由、更高效和更方便等諸多優(yōu)點,可對于不十分熟悉指針的朋友來說,用起來也許就是災難(常見的就是程序跑飛)
因此,通過指針的使用率大概就能判斷一個人的編程能力水平
請看下面的代碼,運行結果是怎么樣的呢?
//?假設數(shù)組首地址為?0x00004000,符合內存對齊:4的倍數(shù) static?unsigned?char?sg_arrBuf[100];? int?main() { ????memset(sg_arrBuf,?0,?sizeof(sg_arrBuf)); ????//?地址為?0x00004000 ????uint8_t?*pucVal?=?(uint8_t?*)&sg_arrBuf[0]; ????//?地址為?0x00004001 ????uint16_t?*puiVal?=?(uint16_t?*)&sg_arrBuf[1]; ????*pucVal?=?20;???//?HEX:?0x14 ????*puiVal?=?2000;?//?HEX:?0x07d0 ????printf("HEX:?"); ????for?(int?i?=?0;?i?3;?i++) ????{ ????????printf("%02x?",?sg_arrBuf[i]); ????} ????printf(" "); ????return?0; }
很多朋友期望的結果如下(小端模式):
HEX:?14?d0?07
事實真的一定如此嗎?
不一定!
也許部分朋友在自己電腦上打開 VS 復制粘貼運行了,編譯后運行,結果還真和上面一樣!??!你這不是在忽悠人嗎?。?!
那有試過在 MCU 上跑過嗎?是不是程序跑飛了?
為什么?
當計算機讀取或寫入內存地址時,它將以字(word)大小的塊進行存儲。數(shù)據(jù)對齊意味著將數(shù)據(jù)放在等于字長的倍數(shù)的內存偏移處,正是由于這種CPU處理內存的方式從而提高了系統(tǒng)的性能。大多數(shù)CPU只能訪問內存對齊的地址。
意味著部分系統(tǒng)架構體系對于未對齊的地址進行訪問時會發(fā)生異常,如果嘗試去訪問內存未對齊的變量進行操作會導致總線錯誤。它只支持對齊訪問。
比如我們訪問一個 4 字節(jié) (Double Word) 型的變量時,如果這個變量的起始地址是能被 4 整除的話,我們說這種訪問是雙字節(jié)對齊的。如果訪問一個 2 字節(jié) ( Word ) 變量,當起始地址能被 2 整除時是對齊的。訪問字節(jié) ( Byte ) 型變量,總是對齊的。
根據(jù)這個就能很快鎖定問題原因了,那就是程序運行到這個位置就導致總線錯誤,從而跑飛了。
//?地址為?0x00004001,未對齊 *puiVal?=?2000;?//?HEX:?0x07d0
預防及解決措施
關于上述的寫法,有些朋友可能在電腦端實現(xiàn)了某個功能,電腦測試沒有任何問題,但是一旦移植到 MCU 上就不行,那么抓緊檢查一下是不是這個問題呢。
因此,為了確保我們的代碼有很高的移植性和穩(wěn)定性,那么一定要預防這種情況,可以通過采用訪問字節(jié) ( Byte ) 型變量,也可以使用memcpy的方式處理這種操作就能避免這種問題。
//?假設數(shù)組首地址為?0x00004000,符合內存對齊: 4的倍數(shù) static?unsigned?char?sg_arrBuf[100];? int?main() { ????memset(sg_arrBuf,?0,?sizeof(sg_arrBuf)); ????uint8_t?ucVal?=?20; ????uint16_t?uiVal?=?2000; ????memcpy(&sg_arrBuf[0],?&ucVal,?1); ????memcpy(&sg_arrBuf[1],?&uiVal,?2); ????printf("HEX:?"); ????for?(int?i?=?0;?i?3;?i++) ????{ ????????printf("%02x?",?sg_arrBuf[i]); ????} ????printf(" "); ????return?0; }? 編輯:黃飛
?
?
?
評論
查看更多