_cdecl和_stdcall的区别

本文通过具体的C语言代码示例,详细对比了_stdcall和_cdecl两种函数调用约定在参数传递及栈清理方面的差异。通过汇编代码直观展示了不同调用约定下函数参数的压栈顺序和栈清理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

     废话不多说,请直接看代码:

 

#include <stdio.h>
int _stdcall Add(int a, int b)
{
	return a+b;
}
void main()
{

	int c = Add(3,4);
	printf("c = %d\n", c);
}

我们现在就取main函数中,两个语句之间的汇编代码,从而来实质性的区别两种调用规则。

	int c = Add(3,4);
0041141E  push        4    
00411420  push        3    
00411422  call        Add (4111DBh) 
00411427  mov         dword ptr [c],eax 
	printf("c = %d\n", c);
 
现在,我们将Add前的_stdcall换成_cdcel看看,结果有什么不同。
#include <stdio.h>
int _cdecl Add(int a, int b)
{
	return a+b;
}
void main()
{

	int c = Add(3,4);
	printf("c = %d\n", c);
}


 
 
新的结果是:
int c = Add(3,4);
0041141E  push        4    
00411420  push        3    
00411422  call        Add (4111E0h) 
00411427  add         esp,8 
0041142A  mov         dword ptr [c],eax 
	printf("c = %d\n", c);

这两种汇编结果的不同之处相信大家一眼可以看出来。后者在函数返回值被赋给c之前,有主调用者(main)来清理了Add函数的参数

栈空间,而前者是由Add函数自身来清理的。入参的顺序都是一样的,这个没有区别,关键在与清理参数的执行者不同。为此,我还是将_stdcall调用的清理过程列出来比较好,大家可以一下子有清新的认识。
 
int _stdcall Add(int a, int b)
{
004113C0  push        ebp  
004113C1  mov         ebp,esp 
004113C3  sub         esp,0C0h 
004113C9  push        ebx  
004113CA  push        esi  
004113CB  push        edi  
004113CC  lea         edi,[ebp-0C0h] 
004113D2  mov         ecx,30h 
004113D7  mov         eax,0CCCCCCCCh 
004113DC  rep stos    dword ptr es:[edi] 
	return a+b;
004113DE  mov         eax,dword ptr [a] 
004113E1  add         eax,dword ptr [b] 
}
004113E4  pop         edi  
004113E5  pop         esi  
004113E6  pop         ebx  
004113E7  mov         esp,ebp 
004113E9  pop         ebp  
004113EA  ret         8   

看到最后一句:ret 8就是清理过程。这下子,明白了吧。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值