您的位置:首页 > 其它

GCC 编译试验:引用变量和循环优化

2010-02-27 15:19 399 查看
(1)引用变量

C++中的指针和引用就像两兄弟,他们几乎有着相同的功能,在大多数情况下都可以互相替换。指针可用CPU间接寻址来实现,其执行效率会比寄存器寻址要慢。引用常被说成是一种别名,可是CPU指令系统里并没有引用和别名这类东西,那么它是如何实现的呢?它会比指针更快吗?为搞明白这个问题,我做了一次试验。

对下面这点代码:

void test1(int *i)

{

(*i) ++;

}

void test2(int &i)

{

i ++;

}
先用gcc编译,然后用objdump反编译

$ gcc -O2 -c pointer_and_reference.cpp

$ objdump -d pointer_and_reference.o
得到:

00000000 <_Z5test1Pi>:

0: 55 push %ebp

1: 89 e5 mov %esp,%ebp

3: 8b 45 08 mov 0x8(%ebp),%eax

6: 83 00 01 addl $0x1,(%eax)
; i++

9: 5d pop %ebp

a: c3 ret

b: 90 nop ; 我没有看懂
这两句干什么用的

c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi

00000010 <_Z5test2Ri>:

10: 55 push %ebp

11: 89 e5 mov %esp,%ebp

13: 8b 45 08 mov 0x8(%ebp),%eax

16: 83 00 01 addl $0x1,(%eax)
; i++

19: 5d pop %ebp

1a: c3 ret
除了我没有看懂的两行代码(在ret之后的奇怪指令),其余代码完全一样。可见引用其实就是用指针实现,两者在效率上并没有差别。

(2)循环优化


C语言写循环还是优点麻烦,通常是会这样写:

int i;

for (i = 0; i < 100; i ++)

{

......

}
其实这个循环很简单,就是要里面的语句循环100遍,i=0、i<100、i++这三条语句显得有些累赘。不知道GCC能否明白我的意图,用最高效的方式实现循环呢?

对下面这段程序:

int test_for()

{

int i;

int j=0;

for (i = 0; i < 100; i ++)

j += i + 1;

return j;

}
函数的作用就是返回从1加到100的结果,小学生都知道结果是5050。若不启用编译优化,其编译结果是:

00000000 <test_for>:

0: 55 push %ebp

1: 89 e5 mov %esp,%ebp

3: 83 ec 10 sub $0x10,%esp

6: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp) ;j=0

d: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%ebp) ;i=0

14: eb 0d jmp 23 <test_for+0x23> ;跳到23

16: 8b 45 f8 mov -0x8(%ebp),%eax ;j = i + 1

19: 83 c0 01 add $0x1,%eax

1c: 01 45 fc add %eax,-0x4(%ebp)

1f: 83 45 f8 01 addl $0x1,-0x8(%ebp) ;i ++

23: 83 7d f8 63 cmpl $0x63,-0x8(%ebp) ;i < 100就跳到16

27: 7e ed jle 16 <test_for+0x16>

29: 8b 45 fc mov -0x4(%ebp),%eax ;返回值=j

2c: c9 leave

2d: c3 ret
这几乎就是把上面源程序组条编译的结果,没有任何优化。没关系,用编译优化再试一次(加-O2参数),得到结果:

00000000 <test_for>:

0: 55 push %ebp

1: b8 ba 13 00 00 mov $0x13ba,%eax ;返回值=5050

6: 89 e5 mov %esp,%ebp

8: 5d pop %ebp

9: c3 ret

a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi ;这句再次没看懂

不得了了!GCC不需要生成循环代码,直接把正确结果编译出来了!实在是太神奇了!

可是上面几乎是最标准的循环写法,在实际编程中,我们常常写一些不标准的循环语句,GCC能否有一样的优化结果呢?

编译下面这段程序:

int test_for2()

{

int i=0;

int j=0;

for (; i < 100; j += i + 1, i ++);

return j;

}

int test_while()

{

int i=0;

int j=0;

while (i < 100) {

j += i + 1;

i ++;

}

return j;

}

int test_while2()

{

int i=0;

int j=0;

while (1) {

j += i + 1;

if (++ i >= 100)

break;

}

return j;

}
每个函数编译得到的结果和上一次得到的完全一样,在这里就不打印出来了。此刻,我心里对GCC佩服得五体投地。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: