VC++函数参数压栈顺序

今天闲来无事写了一段代码:
int Func1(int x,int y){
	return (x&y)+((x^y)>>1);
}
void main(){
        int Array[] = {1,2,3,4,5};
	int *ptr = Array;
	int c = Func1(*ptr,*(++ptr));
	printf("%d\n",c);
}

原本预想输出结果应该为1,谁知竟然为2,百思不得姐之后,就调试了下进入反汇编查看其中奥妙:

55:       int Array[] = {1,2,3,4,5};
00401088   mov         dword ptr [ebp-14h],1
0040108F   mov         dword ptr [ebp-10h],2
00401096   mov         dword ptr [ebp-0Ch],3
0040109D   mov         dword ptr [ebp-8],4
004010A4   mov         dword ptr [ebp-4],5
这个过程就不用解释了,预先计算数组大小,数组按内存地址从低位到高位分配,接下来:
56:       int *ptr = Array;
004010AB   lea         eax,[ebp-14h]
004010AE   mov         dword ptr [ebp-18h],eax
注意mov和lea的区别,如果你认为lea eax,[ebp-18h]是将内存地址为ebp-14h中的内容赋给eax那就错了,lea只是将内存地址赋给eax,也就是此时eax的内容是ebp-14h。对于指令mov eax,[ebp-14h]自然是将内存中的地址压入eax。说到这里就啰嗦一下,mov的右值必须为常量不能为表达式,如, 可以写MOV EAX, EBP,但不能写MOV EAX, EBP + 8 这是因为EBP + 8本身也需要一条指令来计算,所以不能跟MOV写在一条指令里。但是汇编指令中内存地址符可以做算术运算,所以对于指令MOV EAX, [EBP + 8]完全是合法的。接下来继续跟下一条指令:

57:       int c = Func1(*ptr,*(++ptr));
004010B1   mov         ecx,dword ptr [ebp-18h] //ecx赋值为ebp-14h
004010B4   add         ecx,4  //ecx值为ebp-10h,指向Array[1]
004010B7   mov         dword ptr [ebp-18h],ecx  
004010BA   mov         edx,dword ptr [ebp-18h]  
004010BD   mov         eax,dword ptr [edx]   //Array[1]压入eax
004010BF   push        eax   //2
004010C0   mov         ecx,dword ptr [ebp-18h]
004010C3   mov         edx,dword ptr [ecx] //ecx值为ebp-10h,指向Array[1]
004010C5   push        edx  //2
004010C6   call        @ILT+0(Func1) (00401005)
004010CB   add         esp,8  
004010CE   mov         dword ptr [ebp-1Ch],eax
根据以上指令我们可以判断该函数参数的入栈顺序为从右至左,所以先执行了++ptr指令,我们继续往下跟:

58:       printf("%d\n",c);
004010D1   mov         eax,dword ptr [ebp-1Ch]
004010D4   push        eax
004010D5   push        offset string "%d\n" (0043101c)
004010DA   call        printf (004081f0)
004010DF   add         esp,8
很明显,ebp-1Ch为局部变量c的地址,在printf中居然也是先将c压栈,然后才是那一串格式控制字符串,这个平时居然没有注意,那么对于以下代码该输出多少呢?int i=0;printf("%d,%d,%d",++i,i,--i);输出该是0,-1,-1,而不是想当然的1,1,0。这个问题可以继续深入的探讨下去,通过查阅资料,得到如下结论:

1. 参数入栈顺序是和具体 编译器实现相关的。比如,Pascal语言中参数就是从左到右入栈的,有些语言中还可以通过修饰符进行指定,如Visual C++。

2. Pascal语言不支持可变长参数,而C语言支持这种特色,正是这个原 因使得C语言函数参数入栈顺序为从右至左。具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。

3. 这里面还牵涉到一个新的问题:标准调用_stdcall和C调用_cdecl,这两种调用方式可等到以后用到时在仔细区别。

最后,对于Func1函数的功能做个说明,这是个面试据说会考到的问题,它的作用是求两输入参数的平均值。

完-----------------------------^o^








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值