(嵌入式C C++語言精華 筆記3)
資料指標
在嵌入式系統的實際調試中,多藉助c語言指標所具有的對絕對位址單元內容的讀寫能力。以指標直接操作記憶體多發生在
如下幾種情況:
(1)某I/O晶片被定位在CPU的儲存空間而非I/O空間,而且寄存器對應於某特定地址。
(2)兩個CPU之間以雙連接埠RAM通訊,CPU需要在雙連接埠RAM的特定單元(mail box)書寫內容以在對方CPU產生中斷。
(3)讀取在ROM或FLASH的特定單元所燒錄的漢字和英文字摸。
unsigned char *p = (unsigned char *) 0xF000FF00;
*p = 11;
(p++; p == 0xF000FF01;)
意義:在絕對位址0xF0000+0xFF00(80186使用16位段地址和16位位移地址)寫入11。
int *p = (int *)0xF000FF00;
p++ -----> p = p + sizeof(int);
p-- -----> p = p - sizeof(int);
注意:CPU以位元組為單位編址,而C語言指標以指向的資料類型長度作自增和自減。
函數指標
理解三個問題:
(1) C語言中函數名直接對應於函數產生的指令代碼在記憶體中的地址,因此函數名可以直接賦給指向函數的指標。
(2)調用函數實際上等同於“調轉指令+參數傳遞處理+迴歸位置入棧”,本質上最核心的操作是將函數產生的目標代碼的首
地址賦給CPU的PC寄存器。
(3)因為函數調用的本質是跳轉到某一個地址單元的code去執行,所以可以“調用”一個根本不存在的函數實體。
《微電腦原理》中講到,186CPU啟動後跳轉至絕對位址0xFFFF0(對應 C語言指標是 0xF000FFF0, 0xF000為
段地址, 0xFFF0為段內位移)執行,如例:
typedef void (*lpFunction) ();/*定義一個無參數,無傳回型別的函數指標類型
*/
/*定義一個函數指標
,指向CPU啟動後所執行第一條指令的位置*/
lpFunction lpReset = (lpFunction)0xF000FFF0;
lpReset(); /*調用函數*/
上述代碼實現了“軟開機”的作用。
數組 VS.動態申請
嵌入式系統中任何不經意的記憶體泄露都會很快導致系統的崩潰。所以一定要保證malloc和free成對出現(原則:誰申請,
就由誰釋放。否則會導致代碼的耦合度增大)。
記憶體申請原則:
(1)儘可能的選用數組,數組不能越界訪問。
(2)如果使用動態申請,則申請後一定要判斷是否申請成功了,並且malloc和free應成對出現。
(值結果參數,值參數)
關鍵字 const
const意味著唯讀。
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
在編譯階段需要的常數只能以#define 宏定義!
故在c語言中如下程式是非法的:
const int SIZE = 10;
char a[SIZE]; /*便宜階段不能用到變數*/
關鍵字 volatile 防止編譯器最佳化
volatile 變數可能用於如下幾種情況:
(1)平行裝置的硬體寄存器(如:狀態寄存器)
(2)一個中斷服務子程式中會訪問到的非自動變數(也就是全域變數)
(3)多線程應用中被幾個任務共用的變數。
CPU字長與儲存空間位寬不一致的處理
80186的字長為16,而NVRAM的位寬為8,在這種情況下,我們需要為NVRAM提供讀寫位元組,字的介面,如下:
typedef usigned char BYTE;
typedef usigned int WORD;
/* 函數功能: 讀NVRAM中的位元組
參數:wOffset, 讀取位置相對NVRAM 基地址的位移
返回:讀取到的位元組值
*/
extern BYTE ReadByteNVRAM(WORD wOffset)
{
LPBYTE lpAddr = (BYTE*) (NVRAM + wOffset * 2); /* 為什麼要乘2? */
return *lpAddr;
}
/* 函數功能: 讀NVRAM中的字
參數:wOffset, 讀取位置相對NVRAM 基地址的位移
返回:讀取到的字
*/
extern WORD ReadWordNVRAM(WORD wOffset)
{
WORD wTmp = 0;
LPBYTE lpAddr;
/* 讀取高位位元組*/
lpAddr = (BYTE*) (NVRAM + wOffset *2); /* 為什麼要乘2? */
wTmp += (*lpAddr) *256;
/* 讀取低位位元組*/
lpAddr = (BYTE*)(NVRAM + (wOffset +1)*2); /* 為什麼要乘2? */
wTmp += *lpAddr;
return wTmp;
}
/* 函數功能: 向NVRAM中寫一個位元組
參數:wOffset, 寫入位置相對NVRAM 基地址的位移
byData, 欲寫入的位元組
*/
extern void WriteByteNVRAM(WORD wOffset, BYTE byData)
{
......
}
/* 函數功能: 向NVRAM中寫一個字
參數:wOffset, 寫入位置相對NVRAM 基地址的位移
byData, 欲寫入的字
*/
extern void WriteWordNVRAM (WORD wOffset, WORD wData)
{
.......
}
_______ _________
cpu | A3--------A2 | |
80186 | A2-------A1 | |
| A1-------A0 | NVRAM |
| A0 | |
_______| |_________|
16位80186與8位NVRAM之間互連只能以地址線A1對其A0,CPU本身的A0與NVRAM不串連,因此,NVRAM的地址只能
是偶數地址,故每次以0x10為單位前進!