现在的位置: 首页 > 综合 > 正文

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

2013年12月11日 ⁄ 综合 ⁄ 共 2186字 ⁄ 字号 评论关闭

 

作者:于连庆,华清远见嵌入式培训中心讲师。

看一个简单的例子,我们期望通过这个函数对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开发视频 物联网培训 物联网技术视频 嵌入式学习    

抱歉!评论已关闭.