相信C語言的使用者對++/–運算符不會陌生吧。又是前綴,又是後綴的++/–一定讓你感到困惑吧!其實以前我也是這樣的,不過在學習了彙編以後,我看了C語言生成的彙編代碼,這才徹底的理解了++/–運算符。
先從最簡單的++運算符開始吧。
int main(void)
{
int a=0;
a++;
++a;
return 0;
}
彙編代碼
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
subl $4,%esp
movl $0,-4(%esp);a=0
addl $1,-4(%esp);a++
addl $1,-4(%esp);++a
movl $0,%eax
leave
ret
a++等於addl $1,-4(%esp)
++a等於addl $1,-4(%esp)
複雜點的。
int main(void)
{
int a=0;
int b=3;
a=b++;
a=++b;
return 0;
}
彙編代碼
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl $0,-4(%ebp);a
movl $3,-8(%ebp);b
//a=b++
movl -8(%ebp),%eax
addl $1,-8(%ebp)
movl %eax,-4(%ebp)
//a=++b
addl $1,-8(%ebp)
movl -8(%ebp),%eax
movl %eax,-4(%ebp)
movl $0,%eax
leave
ret
a=b++先將b的值放入%eax中,再b=b+1,再將%eax的值放入a中。
a=++b先b=b+1,在將b賦值給a。
如果是放入printf函數的參數中呢?
int main(void)
{
int a=0;
printf("%d %d\n",a++,1);
printf("%d %d\n",++a,1);
return 0;
}
彙編代碼
.section .rodata
.LC0:.string "%d %d\n"
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
subl $4,%esp
movl $0,-4(%ebp)
pushl $1
pushl -4(%ebp)
addl $1,-4(%ebp)
pushl $.LC0
call printf
addl $12,%esp
pushl $1
addl $1,-4(%ebp)
pushl -4(%ebp)
pushl $.LC0
call printf
addl $12,%esp
movl $0,%eax
leave
ret
棧裏先存放立即數1,再存放a,再a=a+1,再存放.LC0的地址,調用printf。
棧裏先存放立即數1,再a=a+1,再存放a,再存放.LC0的地址,調用printf。
困難級別的。
int main(void)
{
int a=0;
int b=1;
a=b+++b+2;
a=++b+b+2;
return 0;
}
彙編代碼
.text
.global main
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl $0,-4(%ebp)
movl $1,-8(%ebp)
movl -8(%ebp),%eax
addl $1,-8(%ebp)
addl %eax.%eax
addl $2,%eax
movl %eax,-4(%ebp)
addl $1,-8(%ebp)
movl -8(%ebp),%eax
addl -8(%ebp),%eax
addl $2,%eax
movl %eax,-4(%ebp)
movl $0,%eax
leave
ret
a=b+++b+2 movl -8(%ebp),%eax 先將b的值放入%eax中,然後%eax代表b,addl $1,-8(%ebp) b=b+1
addl %eax.%eax %eax+%eax,addl $2,%eax %eax+%eax+2得到結果放入a中、
a=++b+b+2 addl $1,-8(%ebp) b=b+1 a=b+b+1。
–運算符等同於++運算符。
由於++/–過於複雜,所以我建議在一般情況下不使用++/–,只在++/–是一條語句的時候使用