嵌入式程序設計之玩轉內存
掃描二維碼
隨時隨地手機看文章
數(shù)據(jù)指針
在嵌入式系統(tǒng)編程中,經(jīng)常會對特定的內存單元進行讀寫操作。在匯編中有對應的MOV指令,而在C/C++以及其他高級語言中基本沒有直接操作絕對地址的能力。而在嵌入式系統(tǒng)的實際開發(fā)調試過程中,大多情況會借助C語言指針多具備的對絕對地址單元內容的讀寫能力。
直接使用指針操作內存,主要分為以下幾種情況:
-
某I/O芯片被定位在CPU的存儲空間而非I/O空間,而且寄存器對應的是特定的地址
-
兩個CPU之間以雙端口RAM進行通信,CPU需要在雙端口RAM的特定單元(mail box)書寫內容以在對方CPU產(chǎn)生中斷。
-
讀寫ROM或FLASH的特定單元所燒錄的漢字或英文字模
////< 在絕對地址0x01寫入10 unsigned char *p = (unsigned char *)0x01; *p = 10;
使用絕對地址時,需要注意指針自增自減的結果取決于指針指向的數(shù)據(jù)類型。
int *p = (int *)0x01;
p++的結果為:p = p + sizeof(int)
p--的結果為:p = p - sizeof(int)
cpu以字節(jié)為單位編址,而C語言指針以指向的數(shù)據(jù)類型長度作為自增自減
函數(shù)指針
-
C 語言中函數(shù)名直接對應于函數(shù)生成的指令代碼在內存中的地址,因此函數(shù)名可以直接賦給指向函數(shù)的指針
-
調用函數(shù)實際上等同于"調轉指令+參數(shù)傳遞處理+回歸位置入棧",本質上最核心的操作是將函數(shù)生成的目標代碼的首地址賦給CPU 的PC 寄存器
-
因為函數(shù)調用的本質是跳轉到某一個地址單元的code 去執(zhí)行,所以可以"調用"一個根本就不存在的函數(shù)實體
typedef void (*lpFunction) ( ); ////< 定義一個無參數(shù)、無返回類型的函數(shù)指針類型 ////< 定義一個函數(shù)指針,指向CPU 啟動后所執(zhí)行第一條指令的位置 lpFunction lpReset = (lpFunction)0xF000FFF0; lpReset(); ////< 函數(shù)調用
《微型計算機原理》中講到,186 CPU 啟動后跳轉至絕對地址0xFFFF0,該地址對應到C語言中為上述例子中的0xF000FFF0,其中0xF000為段地址,0xFFF0為段內偏移。
在上述例子中,根本沒有定義函數(shù),但是卻能夠執(zhí)行l(wèi)pReset()函數(shù)的調用,它實際的作用為"軟重啟",使程序跳轉到CPU啟動后第一條要執(zhí)行的執(zhí)行位置。
動態(tài)申請內存
在嵌入式系統(tǒng)中動態(tài)內存申請存在比一般系統(tǒng)編程時更嚴格的要求,這是因為嵌入式系統(tǒng)的內存空間往往是十分有限的,不經(jīng)意的內存泄露會很快導致系統(tǒng)的崩潰。
因此,maloc和free一般要保證成對出現(xiàn)。
char *Function(void) { char *p = NULL; p = (char *)malloc(sizeof(char)); ... return p; } void main() { char *q = Function(); ... free(q); }
上面這個例子明顯是不合理的,因為它違反了"誰申請,就由誰釋放"的原則。若程序不滿足這個原則的話,會導致代碼的耦合度增大,使用者需要在調用的時候知道Function()函數(shù)中的具體實現(xiàn)。
正確做法應該如下:
void Function(char*p) { ... } void main() { char *q = malloc(sizeof(char)); ... Function(q); ... free(q); }