关于_stdcall和_cedcl到底谁弹栈?
本帖最后由 EDDGA 于 2013-02-15 00:36:55 编辑 看了关于_stdcall和_cdecl约定,
1、其中一个区别是由调用者还是被调用者弹出栈,这个调用者和被调用者指的是什么?对象?函数?用户?编译器?。
2、百度写_stdcall是“自己在退出时清栈”,而_cdecl则“每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大”。只着眼于两者都可以用的情况,看起来_stdcall比_cdecl好,那是不是意味着全局函数、类方法、实例方法甚至构造函数和析构函数统统都应尽可能用_stdcall?
3、写_stdcall等约定时,.h和.cpp中的函数都要写明是_stdcall吗?我试了下,h写_stdcall而cpp不写也是行的,但我又不明白h写_stdcall而cpp不写,两个函数还是同一个函数吗?
网上写的_stdcall和_cdecl的文章多是千篇一律,而我道行太浅看不明白,指各位指点一下,谢谢
[解决办法]
int func1()
{
...
}
int func2(){//func2 调用func1, func2是调用者;func1是被调用者
func1();
}
int main(){//main是调用者;func2是被调用者
func2();
...
}
[解决办法]
在这种编译程序中,函数是通过堆栈传递参数。编译程序遇到函数调用时,要先把参数一个个按顺序压入堆栈。函数内部代码就是从堆栈中访问参数。这里并不把参数弹出堆栈,而是通过 base 寄存器来访问。函数退出是通过 ret 指令。如果是被调用者(也就是函数本身)负责清栈,ret 指令后面要跟一个数字,表示清栈字节数。例如,调用时有两个整数参数,就要写成 ret 8,这样返回时就自动把堆栈清掉 8 个字节。如果是调用者负责清栈,ret 就不带数字,但编译程序会在调用返回后清掉这 8 个字节。
[解决办法]
问题1,2:
假设fun1, fun2(cdecl), fun3(stdcall), fun1调用fun2, fun3.
编译器编译fun1时, 会在调用fun2后, 加入汇编来清理栈上面的传给fun2的参数.
编译器编译fun3时, 会在fun3返回前, 加入汇编来清理栈上面fun1传进来的参数.
问题3:
默认都是cdecl, 所以不写也无所谓. 但是stdcall最好都写上.