文章編號:1672-5913(2008)06-0098-02
摘要:本文探討了基于C語言的ARM嵌入式程序設計課程中學生反映不好掌握的一些知識點。
關鍵詞:ARM嵌入式;C語言;程序設計;技巧
中圖分類號:G642
文獻標識碼:B
引言
嵌入式C語言程序設計是利用基本的C語言知識,面向嵌入式工程實際應用進行程序設計語言。如何能夠在嵌入式系統(tǒng)開發(fā)中熟練、正確地運用C語言開發(fā)出高質量的應用程序,是學習嵌入式程序設計的關鍵。下面介紹基于C語言的ARM嵌入式程序設計課程中學生反映不好掌握的一些難點。
1變量定義
先看下面一個例子:
char a; char a;
short b; char c;
char c; short b;
int d; int d;
這里定義的4個變量形式都一樣,只是次序不同,卻導致了在最終映像中不同的數(shù)據(jù)布局,如圖1所示。顯然,第2種方式節(jié)約了更多的存儲空間(Pad為無意義的填充數(shù)據(jù))。
由此可見,在變量聲明時,最好把所有相同類型的變量放在一起定義,這樣可以優(yōu)化存儲器布局。
圖1變量在數(shù)據(jù)區(qū)里的布局
對于局部變量類型的定義,一般情況下,人們總是設法使用short或char來定義變量,以節(jié)省存儲空間;但是,當一個函數(shù)的局部變量數(shù)目有限時,其結果恰恰相反。因為編譯器會把局部變量分配給內部寄存器,每個變量占用一個寄存器,如圖2所示。假定a1是任意可能的寄存器存儲函數(shù)的局部變量,同樣完成加1的操作,32位的int型變量最快,只用1條加法指令。而8位和16位變量,完成加法操作后,還需要在32位的寄存器中進行括號擴展,其中有符號的變量,要用邏輯左移(LSL)和算術右移(ASR)2條指令才能完成符號擴展;無符號的變量,要使用1條邏輯“與”(AND)指令對符號位進行清0。所以,使用32位int或unsingedint局部變量最有效率。
圖2不同類型局部變量的編譯結果
變量定義中,為了精簡程序,程序員總是竭力避免使用冗余變量。通常情況下這是正確的,但也有例外。
例如:冗余變量的使用與否比較。
int f(void);
int g(void);
int errs;
void test1(void)
{
errs+=f();
errs+=g();
}
void test2(void)
{
int localerrs=errs;
localerrs+=f();
localerrs+=g();
errs=localerrs;
}
在第一種情況test1()里,每次訪問全局變量errs時,都要先從相應的存儲器Load到寄存器里,經(jīng)f()或g()函數(shù)調用后再Store回原來的存儲區(qū)里面。在這個例子里,一共要進行2次這樣的Load/Store操作(第一次是Load,第2次是Store)。而在第2種情況test2()里,局部變量localerrs被分配以寄存器,這樣一來,整個函數(shù)就只需1次Load/Store訪問全局變量存儲器。減少存儲器訪問的次數(shù)對于系統(tǒng)性能的改善是非常有好處的。
2參數(shù)傳遞
為了使單獨編譯的C語言程序和匯編程序能夠互相調用,定義了統(tǒng)一的函數(shù)過程調用標準ATPCS(ARM-Thumb Procedure Call Standard)。ATPCS定義了寄存器組中的{R0~R3}作為參數(shù)傳遞和結果返回寄存器。如果參數(shù)數(shù)目超過4個,則使用堆棧進行傳遞。由于內部寄存器的訪問速度遠遠大于存儲器,所以要盡量使參數(shù)傳遞在寄存器里面進行,即應盡量把函數(shù)的參數(shù)控制在4個以下。例如:從C語言中直接調用匯編語言函數(shù):
extern void strcopy(char *d,const char *s);
int main(void){
const char src=“Source”;
char dest[10];
…
strcopy(dest,src);
…
}
AREAStrCopy,CODE,READONLY
EXPORT strcopy
strcopy
LDRBR2,[R1],#1
STRBR2,[R0],#1
CMP R2,#0
BNE strcopy
MOVPC,LR
END
例子中的函數(shù)strcopy(dest,src)用匯編來實現(xiàn)。根據(jù)ATPCS的定義,函數(shù)參數(shù)從左到右由寄存器進行傳遞,所以在匯編中可直接由R0和R1進行引用。這樣,在C語言和匯編語言之間進行相互調用就容易實現(xiàn)了。
3循環(huán)條件
計數(shù)循環(huán)是程序中十分常用的流程控制結構。在C語言中,常用下面累加計數(shù)的循環(huán)形式:
for(loop=1;loop<=limit;loop++)
這種累加計數(shù)的方法符合一般的自然思維習慣,所以下面這種遞減計數(shù)方法很少使用:
for(loop= limit;loop!=0;loop--)
這2種循環(huán)形式在邏輯上并沒有效率差異,但是映射到具體的體系結構中時,就產生了很大的不同,如圖3所示。
圖3不同的循環(huán)條件設置比較
從圖中可以發(fā)現(xiàn),累加法比遞減法多用了1條指令,當循環(huán)次數(shù)比較大時,這2段代碼就會在性能上產生明顯的差異。
其本質原因是:當進行一個非0常數(shù)比較時,必須用專門的CMP指令來執(zhí)行;而當一個變量與0進行比較時,ARM指令則可直接利用條件執(zhí)行的特性(NE)來進行判別。因此,在ARM的體系結構下編程,最好采用遞減至0的方法來設置循環(huán)條件。
參考文獻
[1] 梁合慶等. 從C到嵌入式C編程語言[M]. 北京航空航天大學出版社,2000.
[2] 田澤. 嵌入式系統(tǒng)開發(fā)與應用[M]. 北京航空航天大學出版社,2005.
[3] 杜春雷. ARM體系結構與編程[M]. 北京:清華大學出版社,2003.
[4] 桑楠. 嵌入式系統(tǒng)原理及應用開發(fā)技術[M]. 北京航空航天大學出版社,2002.