您的位置:首页 > 其它

__cdecl和__stdcall的区别

2006-12-23 23:34 302 查看
函数调用规范__cdecl和__stdcall的区别一目了然(表格形式)
[align=left]Posted on Tuesday, May 24, 2005 3:23 PM #C & C++ [/align]
[align=center] [/align]
[align=center]__cdecl[/align]
[align=center] [/align]
[align=center] [/align]
[align=center]__stdcall[/align]
[align=left] [/align]
[align=left]C和C++程序的缺省调用规范[/align]
[align=left] [/align]
[align=left]为了使用这种调用规范,需要你明确的加上__stdcall(或WINAPI)文字。即return-type __stdcall function-name[(argument-list)][/align]
[align=left] [/align]
[align=left] [/align]
[align=left]在调用函数(Callee)返回,由调用者(Caller)调整堆栈。[/align]
[align=left] [/align]
[align=left]调用者[/align]
[align=left] // call function[/align]
[align=left] // adjust stack[/align]
[align=left] [/align]
[align=left]被调用函数[/align]
[align=left] // do work[/align]
[align=left] // return[/align]
[align=left] [/align]
[align=left]在调用函数(Callee)返回,由调用函数(Callee)调整堆栈。图示:[/align]
[align=left] [/align]
[align=left]调用者[/align]
[align=left] // call function[/align]
[align=left] [/align]
[align=left]被调用函数[/align]
[align=left] // do work[/align]
[align=left] // adjust stack[/align]
[align=left] // return[/align]
[align=left] [/align]
[align=left]因为每个调用的地方都需要生成一段调整堆栈的代码,所以最后生成的文件较大。[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]因为调整堆栈的代码只存在在一个地方(被调用函数的代码内),所以最后生成的文件较小。[/align]
[align=left] [/align]
[align=left]函数的参数个数可变(就像printf函数一样),因为只有调用者才知道它传给被调用函数几个参数,才能在调用结束时适当地调整堆栈。[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]函数的参数个数不能是可变的。[/align]
[align=left] [/align]
[align=left]对于定义在C程序文件中的输出函数,函数名会保持原样,不会被修饰。[/align]
[align=left]对于定义在C++程序文件中的输出函数,函数名会被修饰, MSDN说Underscore character (_) is prefixed to names. 我实际测试(VC4和VC6)下来发现好像不是那么简单。[/align]
[align=left]可通过在前面加上extern “C”以去除函数名修饰。也可通过.def文件去除函数名修饰。[/align]
[align=left] [/align]
[align=left]不论是C程序文件中的输出函数还是C++程序文件中的输出函数,函数名都会被修饰。[/align]
[align=left]对于定义在C程序文件中的输出函数,An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list.[/align]
[align=left]对于定义在C++程序文件中的输出函数,好像更复杂,和__cdecl的情况类似。[/align]
[align=left]好像只能通过.def文件去除函数名修饰。[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]_beginthread需要__cdecl的线程函数地址[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]_beginthreadex和CreateThread需要__stdcall的线程函数地址[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]两者的参数传递顺序都是从右向左。[/align]
[align=left]为了让VB可以调用,需要用__stdcall调用规范来定义C/C++函数。请参看Microsoft KB153586 文章:How To Call C Functions That Use the _cdecl Calling Convention。[/align]
[align=left]当你LoadLibrary一个DLL文件后, 把GetProcAddress取得的函数地址传给上面三个线程生成函数时,请务必确认实际定义在DLL文件的输出函数符合调用规范要求。否则,编译成Release版后运行,可能会破坏堆栈,程序行为不可预测。[/align]
[align=left]VC中的相关编译开关:/Gd /Gr /Gz。另外,VC6中新增加的 /GZ 编译开关可以帮你检查堆栈问题。[/align]
[align=left]我也是初学者,若有不对的地方、可以补充的地方,请指教。谢谢。 [/align]
[align=left] [/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: