您的位置:首页 > 其它

(转)函数调用约定--- __cdecl和__stdcal

2013-03-23 11:01 106 查看
调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。

上面这段话摘自[BlueTopic]的BLOG

采 用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。采用__stdcal约定时,函数参数按照从右到左 的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。__fastcall约定将函数的从左边开始的两个大小不大于4个字节(DWORD)的参数分别放在ECX和EDX寄存
器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈。

(上面这段话摘自CSDN)

可见__cdecl和__stdcal之间的唯一区别在于返回时是由被调用者清理栈,还是由调用用者清理栈.

但是,这两种清理栈的方式,会对有什么影响呢?

很感谢 [jxb_memory] 的回答:

_stdcall与_cdecl两者之间的区别:

WINDOWS的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈需要清除,这里就是问题的关键,如何清除??

如果我们的函数使用了_cdecl,那么栈的清除工作是由调用者,用COM的术语来讲就是客户来完成的。这样带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。

如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨(开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。

那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行,因此,这种情况我们只能使用_cdecl。

到这里我们有一个结论,如果你的程序中没有涉及可变参数,最好使用__stdcall关键字(函数)调用约定--- __cdecl和__stdcal
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: