相信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。
–运算符等同于++运算符。
由于++/–过于复杂,所以我建议在一般情况下不使用++/–,只在++/–是一条语句的时候使用