GCC下宏扩展后的++i

听讨论的时候,遇到一题是关于++i*++i的——这样的讨论意义不大,却也可以一窥编译器对相关问题的处理。

原题如下

相关代码说明如下

#include <stdio.h>
#define POWER(X) X*X
int main()
{
int ch = 8;
int sum = POWER(ch++);
sum
= POWER(++ch);
return 0;
}

如果添加printf输出,其第一个sum = 64,第二个sum = 144

将上面的进行汇编编译得到。

gcc -S test.c

程序main的主要汇编代码

main:
pushl %ebp
movl %esp, %ebp
subl $
16, %esp
movl $
8, -8(%ebp)
movl -
8(%ebp), %eax
imull -
8(%ebp), %eax
movl %eax, -
4(%ebp)
addl $
1, -8(%ebp)
addl $
1, -8(%ebp)
addl $
1, -8(%ebp)
addl $
1, -8(%ebp)
movl -
8(%ebp), %eax
imull -
8(%ebp), %eax
movl %eax, -
4(%ebp)
movl $
0, %eax
leave
ret

少去进栈出栈的操作,i++*i++产生的汇编代码是

     movl -8(%ebp), %eax
imull -
8(%ebp), %eax
movl %eax, -
4(%ebp)
addl $
1, -8(%ebp)
addl $
1, -8(%ebp)

++i*++i产生的汇编代码是

addl $1, -8(%ebp)
addl $
1, -8(%ebp)
movl -
8(%ebp), %eax
imull -
8(%ebp), %eax

由上面的代码可以看出

1)i++的自增操作是在整个乘法完成之后才进行的,而++i的操作则是在乘法之前进行。

2)movl和imull总是连续出现,进行乘法的时候,左右的操作数是从同一块内存取出来的,因此计算结果肯定是完全平方数。

找到一篇相似的文章《分析gcc下的i++与++i》gfw),在后续讨论三个i++的情况。后面还有总结,先一并摘抄过来。

++i*i++*++i的汇编代码为  

movl $8, -8(%ebp)
addl $
1, -8(%ebp)
movl -
8(%ebp), %eax
imull -
8(%ebp), %eax
addl $
1, -8(%ebp)
imull -
8(%ebp), %eax
movl %eax, -
4(%ebp)
addl $
1, -8(%ebp)
leave
ret

摘录

分析一下上面的代码,结论就很清晰了,所有的i++操作会在整个表达式计算完后才计算,除了最左边的乘法会从同一块内存取操作数外,后续的乘法的作操作数就是直接取的上次计算的结果。

总结一下:

1.从左向右计算
2.最左边的乘法从同一内存取操作数,因此肯定是完全平方数
3.所有的i
++可以替换成i
4.所有的
++i先计算增一,再取增一后的值
比如计算 i++*++i*++i*i++*++i (i=3): 结果是 4×4×5×5×6=2400.


posted @ 2011-07-01 14:08  westfly  阅读(265)  评论(0编辑  收藏  举报