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开发视频 物联网培训 物联网技术视频 嵌入式学习
看一个简单的例子,我们期望通过这个函数对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开发视频 物联网培训 物联网技术视频 嵌入式学习
相关文章推荐
- iOS开发程序中各种变量的存储位置和程序返回变量的问题
- ARM裸机程序开发15(伪指令,汇编语句格式,汇编变量常量)
- iOS开发程序中各种变量的存储位置和程序返回变量的问题
- 程序开发类的问题方法
- ARM开发问题总结
- VC/VS开发的exe程序运行问题续
- 如何解决开发x64平台下ASP.NET程序的常见问题
- 全局变量,静态局部变量,局部变量空间的堆分配和栈分配问题
- 小程序红包开发跳坑记 微信小程序红包接口开发过程中遇到的问题 微信小程序红包开发
- ARM裸机程序开发17(堆栈寻址)
- 程序笔试题-const变量通过指针修改问题
- 【Linux开发】OpenCV在ARM-linux上的移植过程遇到的问题1---cvNamedWindow调用报错的问题
- VC2005开发移动程序的小问题
- 简单描述为什么编译Android C程序所用的交叉编译工具链是arm-linux-androideabi-xx不是GNU开发的工具链arm-linux-gnueabi-xx?
- GNU tools 开发ARM 程序及生成映象文件机理
- VS为XP开发的程序移植到Win7上遇到两个小的问题及解决办法
- eclipse开发android程序常见问题解决办法
- 开发程序时在主要功能之外应当考虑的问题
- 使用Jrtplib编译的arm程序和pc无法通信的问题
- .net程序开发人员必看的变量的命名规则