首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

调用约定 _cdecl 有什么用?该如何处理

2012-02-19 
调用约定 __cdecl 有什么用?我知道__cdecl是参数入栈方式,但这有什么影响呢?默认的就是__cdecl吧。[解决办

调用约定 __cdecl 有什么用?
我知道   __cdecl   是参数入栈方式,但这有什么影响呢?默认的就是   __cdecl   吧。

[解决办法]
默认的调用约定可以用编译选项修改, 比如 vc :

/Gd __cdecl calling convention
/Gr __fastcall calling convention
/Gz __stdcall calling convention
[解决办法]
cdecl调用约定即C调用约定,是C语言缺省的调用约定
cdecl调用约定的参数压栈顺序是参数首先由右向左压入堆栈。函数本身不清理堆栈,调用者负责清理堆栈。
[解决办法]
stdcall即pascal调用规范,在Microsoft C++系列的C/C++编译器中,常常用PASCAL宏来声明这个调用约定
stdcall的调用约定意味着:
1)参数从右向左压入堆栈;
2)函数自身修改堆栈;
3) 函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸。

fastcall调用约定和stdcall类似,即:
1) 函数的第一个和第二个(从左边计起)DWORD参数(或者尺寸更小的)通过ecx和edx传递, 其他参数通过从右向左的顺序压栈;
2) 被调用函数清理堆栈;
3) 函数名修改规则同stdcall。

thiscall是唯一一个不能明确指明的函数修饰,因为thiscall不是关键字。它是C++类成员函数缺省的调用约定。由于成员函数调用还有一个this指针,因此必须特殊处理,thiscall即:
1) 参数从右向左入栈;
2) 如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定, this指针在所有参数压栈后被压入堆栈;
3) 对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈。

naked call调用规范
编译器不会给这种函数增加初始化和清理代码,更特殊的是,不能用return返回返回值,只能用插入汇编返回结果。这一般用于实模式驱动程序设计。


如果定义的约定和使用的约定不一致,则将导致堆栈被破坏,导致严重问题,
下面是两种常见的问题:
1) 函数原型声明和函数体定义不一致
2) DLL导入函数时声明了不同的函数约定



[解决办法]
举例:
调用函数f(int a,int b,int c),那么参数a,b,c的入栈会有2中可能:
A:
代码表示 | 执行代码后的栈中的内容表示(x是esp寄存器指向的内容)
push a | x a
push b | x-4 b
push c | x-8 c
push eip | x-12 eip
call f
B:
代码表示 | 执行代码后的栈中的内容表示(x是esp寄存器指向的内容)
push c | x c
push b | x-4 b
push a | x-8 a
push eip | x-12 eip
call f

不同的编译器可以选择上面2种形式中的一种来实现参数的传递(C语言中使用的是第2种实现).
__cdecl可以指明该函数参数是以何种形式如栈的。
如果不指明的话,在代码移植的时候就可能会出现问题。
比如在pascal语言中实现了f(int pa,int pb,int pc)函数.而C中调用函数f(a,b,c),如果没有入栈顺序顺序,那么pa, pb, pc获得的值就分别是c,b,a,而不是a,b,c,这样很明显会产生错误.
[解决办法]
应该不一定,同一种语言中也可能会用到,比如你要用什么dll的时候,可能由于特殊原因这个dll虽然是c++开发的,但是考虑到和另外某个语言的兼容使用问题....

热点排行