这个问题是今天逛论坛的时候发现的,原来的问题可以简化为如下的形式:
输出的结果是:
0
1
10
10
查了下舍友的C++ Premier书,优先级的排序是: 后置自增运算符>解引用运算符==前置自增运算符。
于是p1的操作应该是:先对p1进行自增运算,这时p1的新值为1,但是由于p1是后置运算符,表达式的值仍然是p的原值,进行解引用运算时,打印p1的原值,为0;此时p1的值为1;
然后执行同样的操作,打印原值,为1,p1自增,为2;
至此想的都没有什么问题,后来出现的10就不知道是怎么回事了。
查了一下,原来是参数入栈的顺序问题。
写个一般的函数,测试了一下:
以下是用gdb disassemble出来的:
Dump of assembler code for function main(int, char**):
push %rbp
mov %rsp,%rbp
sub $0x20,%rsp
mov %edi,-0x14(%rbp)
mov %rsi,-0x20(%rbp)
movl $0x0,-0x4(%rbp)
movl $0x0,-0x8(%rbp)
mov -0x4(%rbp),%eax
mov %eax,-0xc(%rbp)
addl $0x1,-0x4(%rbp)
addl $0x1,-0x4(%rbp)
mov -0x4(%rbp),%eax
mov %eax,-0x10(%rbp)
mov -0x10(%rbp),%edx
mov -0xc(%rbp),%eax
mov %edx,%esi
mov %eax,%edi
callq 0x4008e4 <func(int, int)>
addl $0x1,-0x8(%rbp)
mov -0x8(%rbp),%eax
addl $0x1,-0x8(%rbp)
mov -0x8(%rbp),%edx
mov %edx,%esi
mov %eax,%edi
callq 0x4008e4 <func(int, int)>
mov $0x2,%esi
mov $0x1,%edi
callq 0x4008e4 <func(int, int)>
mov $0x0,%eax
leaveq
retq
End of assembler dump.
汇编我一点不会(这个是AT&T格式的汇编?),但是最后一个函数调用就可以看出,函数的参数是从右至左进栈的
第二个函数调用,对应的汇编代码是:
addl $0x1,-0x8(%rbp)
mov -0x8(%rbp),%eax
addl $0x1,-0x8(%rbp)
mov -0x8(%rbp),%edx
mov %edx,%esi
mov %eax,%edi
callq 0x4008e4 <func(int, int)>
函数的调用的dump是:
push %rbp
mov %rsp,%rbp
sub $0x10,%rsp
mov %edi,-0x4(%rbp)
mov %esi,-0x8(%rbp)
mov -0x4(%rbp),%eax
这段意思是说,先将右边的参数做+1的运算,然后存入eax;再将这个参数做+1运算,存入edx;
然后将edx入栈,再将eax入栈。调用的时候顺序出栈。从函数第用的dump里也可以看出,参数是以入栈和出栈的方式传给函数的。最后输出的结果就是:
1
2
所以,最好不要在传参的时候做任何运算。