时间:2022-08-27 01:58:43
文章编号:1672-5913(2008)06-0098-02
摘要:本文探讨了基于C语言的arm嵌入式程序设计课程中学生反映不好掌握的一些知识点。
关键词:ARM嵌入式;C语言;程序设计;技巧
中图分类号:G642
文献标识码:B
引言
嵌入式C语言程序设计是利用基本的C语言知识,面向嵌入式工程实际应用进行程序设计语言。如何能够在嵌入式系统开发中熟练、正确地运用C语言开发出高质量的应用程序,是学习嵌入式程序设计的关键。下面介绍基于C语言的ARM嵌入式程序设计课程中学生反映不好掌握的一些难点。
1变量定义
先看下面一个例子:
char a; char a;
short b; char c;
char c; short b;
int
d; int
d;
这里定义的4个变量形式都一样,只是次序不同,却导致了在最终映像中不同的数据布局,如图1所示。显然,第2种方式节约了更多的存储空间(Pad为无意义的填充数据)。
由此可见,在变量声明时,最好把所有相同类型的变量放在一起定义,这样可以优化存储器布局。
图1变量在数据区里的布局
对于局部变量类型的定义,一般情况下,人们总是设法使用short或char来定义变量,以节省存储空间;但是,当一个函数的局部变量数目有限时,其结果恰恰相反。因为编译器会把局部变量分配给内部寄存器,每个变量占用一个寄存器,如图2所示。假定a1是任意可能的寄存器存储函数的局部变量,同样完成加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到寄存器里,经f()或g()函数调用后再Store回原来的存储区里面。在这个例子里,一共要进行2次这样的Load/Store操作(第一次是Load,第2次是Store)。而在第2种情况test2()里,局部变量localerrs被分配以寄存器,这样一来,整个函数就只需1次Load/Store访问全局变量存储器。减少存储器访问的次数对于系统性能的改善是非常有好处的。
2参数传递
为了使单独编译的C语言程序和汇编程序能够互相调用,定义了统一的函数过程调用标准ATPCS(ARM-Thumb Procedure Call Standard)。ATPCS定义了寄存器组中的{R0~R3}作为参数传递和结果返回寄存器。如果参数数目超过4个,则使用堆栈进行传递。由于内部寄存器的访问速度远远大于存储器,所以要尽量使参数传递在寄存器里面进行,即应尽量把函数的参数控制在4个以下。例如:从C语言中直接调用汇编语言函数:
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
例子中的函数strcopy(dest,src)用汇编来实现。根据ATPCS的定义,函数参数从左到右由寄存器进行传递,所以在汇编中可直接由R0和R1进行引用。这样,在C语言和汇编语言之间进行相互调用就容易实现了。
3循环条件
计数循环是程序中十分常用的流程控制结构。在C语言中,常用下面累加计数的循环形式:
for(loop=1;loop
这种累加计数的方法符合一般的自然思维习惯,所以下面这种递减计数方法很少使用:
for(loop= limit;loop!=0;loop--)
这2种循环形式在逻辑上并没有效率差异,但是映射到具体的体系结构中时,就产生了很大的不同,如图3所示。
图3不同的循环条件设置比较
从图中可以发现,累加法比递减法多用了1条指令,当循环次数比较大时,这2段代码就会在性能上产生明显的差异。
其本质原因是:当进行一个非0常数比较时,必须用专门的CMP指令来执行;而当一个变量与0进行比较时,ARM指令则可直接利用条件执行的特性(NE)来进行判别。因此,在ARM的体系结构下编程,最好采用递减至0的方法来设置循环条件。
参考文献
[1] 梁合庆等. 从C到嵌入式C编程语言[M]. 北京航空航天大学出版社,2000.
[2] 田泽. 嵌入式系统开发与应用[M]. 北京航空航天大学出版社,2005.
[3] 杜春雷. ARM体系结构与编程[M]. 北京:清华大学出版社,2003.
[4] 桑楠. 嵌入式系统原理及应用开发技术[M]. 北京航空航天大学出版社,2002.