您的位置:首页 > 其它

ARM程序开发中的冗余局部变量问题

2011-11-08 10:21 176 查看
作者:于连庆,华清远见嵌入式培训中心讲师。
看一个简单的例子,我们期望通过这个函数对2个定时器使用同一个步进量进行更新。
void update_timer(int *timer1, int *timer2, int *step)

{

*timer1 += *step;

*timer2 += *step;

}
在uVision4开发环境下编译,生成的代码如下:
update_timer

0x300003c0: e5903000 LDR r3,[r0,#0]

0x300003c4: e592c000 LDR r12,[r2,#0] ; 装载step

0x300003c8: e083300c ADD r3,r3,r12

0x300003cc: e5803000 STR r3,[r0,#0]

0x300003d0: e5913000 LDR r3,[r1,#0]

0x300003d4: e592c000 LDR r12,[r2,#0] ; 装载step

0x300003d8: e083300c ADD r3,r3,r12

0x300003dc: e5813000 STR r3,[r1,#0]

0x300003e0: e12fff1e BX lr
按照函数参数传递规则,r0对应参数timer1,r1对应timer2,r3对应step。注意编译器装载了step两次,我们期望应该是一次。编译器为什么会这么做?这里涉及到“指针别名”的概念。
所谓“指针别名”,是说当两个指针指向同一个地址对象时,这两个指针就叫做该对象的别名。对其中一个指针进行写入,会影响到从另一个指针的读出。在一个函数中,编译器通常不知道哪一个指针是别名,哪一个不是;或者哪一个指针有别名,哪一个没有。编译器非常悲观地认为,对任何一个指针的写入,都将会影响从任何其它指针的读出。很显然,这明显降低了程序的执行效率。
回到上面的例子,编译器认为指针timer1和指针step会互为别名,也就是说,编译器不能确定对指针timer1的写入是否会影响从指针step的读出。在这种情况下,第2次*step的值将与第1次的不同,编译器不得不增加一条额外的load指令。
解决上述问题可以使用“冗余局部变量”,但这种方法往往和我们的习惯思维相悖。一般情况下,程序员总是竭力避免使用冗余变量,以精简程序。

把上面的代码改写一下:
void update_timer(int *timer1, int *timer2, int *step)

{

int tmp;
tmp = *step;

*timer1 += tmp;

*timer2 += tmp;

}
重新编译,生成的代码如下:
update_timer

0x300003c0: e5923000 LDR r3,[r2,#0] ; 装载step

0x300003c4: e590c000 LDR r12,[r0,#0]

0x300003c8: e08cc003 ADD r12,r12,r3

0x300003cc: e580c000 STR r12,[r0,#0]

0x300003d0: e591c000 LDR r12,[r1,#0]

0x300003d4: e08cc003 ADD r12,r12,r3

0x300003d8: e581c000 STR r12,[r1,#0]

0x300003dc: e12fff1e BX lr
注意编译器只装载了step 一次,与我们期望的一致。
上面的例子表明,增加局部变量后,编译器就不需要担心timer1和step的别名问题了,减少了对存储器的访问次数,减少对存储器的访问次数对提高系统性能是非常有好处的。
嵌入式及3G相关资源及学习请点击:嵌入式开发视频 android开发视频 android培训 3G培训 QT培训 QT开发视频 物联网培训 物联网技术视频 嵌入式学习
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: