调用约定设置不当会造成运行时错误
2008-01-12 11:57
218 查看
/Gd /Gr /Gz 调用方式如果不匹配会造成一些列的运行时错误。
调用声明调用方式为__stdcall的dll函数接口时如果使用__cdecl 调用方式则会产生Run-Time Check Failure #0运行时错误。
下面转一些关于调用方式的资料:
————————————————————————————————————————————————
(1) _stdcall调用
_stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。
WIN32 Api都采用_stdcall调用方式,这样的宏定义说明了问题:
#define WINAPI _stdcall
按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number。
(2) _cdecl调用
_cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。_cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。
由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。关于C/C++中变长参数(…)的问题,笔者将另文详述。
由于Visual C++默认采用_cdecl 调用方式,所以VC中中调用DLL时,用户应使用_stdcall调用约定。
按C编译方式,_cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。
(3) _fastcall调用
_fastcall调用较快,它通过CPU内部寄存器传递参数。
按C编译方式,_fastcall调用约定在输出函数名前面加“@”符号,后面加“@”符号和参数的字节数,形如@functionname@number。
——————————————————————————————————————————————
函数参数入栈的方式
---------------------------------------------------------------
在函数调用过程中,会使用堆栈,这三个表示不同的堆栈调用方式和释放方式。
比如说__cdecl,它是标准的c方法的堆栈调用方式,就是在函数调用时的参数压入堆栈是与函数的声明顺序相反的,其它两个可以看MSDN,不过这个对我们编程没有太大的作用
---------------------------------------------------------------
调用约定
调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。MFC支持以下调用约定:
_cdecl
按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于"C"函数或者变量,修饰名是在函数名前加下划线。对于"C++"函数,有所不同。
如函数void test(void)的修饰名是_test;对于不属于一个类的"C++"全局函数,修饰名是?test@@ZAXXZ。
这是MFC缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。
_stdcall
按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于"C"函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号"@"及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。对于"C++"函数,则有所不同。
所有的Win32 API函数都遵循该约定。
_fastcall
头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于"C"函数或者变量,修饰名以"@"为前缀,然后是函数名,接着是符号"@"及参数的字节数,如函数int func(int a, double b)的修饰名是@func@12。对于"C++"函数,有所不同。
未来的编译器可能使用不同的寄存器来存放参数。
调用声明调用方式为__stdcall的dll函数接口时如果使用__cdecl 调用方式则会产生Run-Time Check Failure #0运行时错误。
下面转一些关于调用方式的资料:
————————————————————————————————————————————————
(1) _stdcall调用
_stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。
WIN32 Api都采用_stdcall调用方式,这样的宏定义说明了问题:
#define WINAPI _stdcall
按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number。
(2) _cdecl调用
_cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。_cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。
由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。关于C/C++中变长参数(…)的问题,笔者将另文详述。
由于Visual C++默认采用_cdecl 调用方式,所以VC中中调用DLL时,用户应使用_stdcall调用约定。
按C编译方式,_cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。
(3) _fastcall调用
_fastcall调用较快,它通过CPU内部寄存器传递参数。
按C编译方式,_fastcall调用约定在输出函数名前面加“@”符号,后面加“@”符号和参数的字节数,形如@functionname@number。
——————————————————————————————————————————————
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码, 所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式 。VC将函数编译后会在函数名前面加上下划线前缀。 _stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压 栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在 函数名后加上"@"和参数的字节数。 _fastcall方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上"@"前 缀,在函数名后加上"@"和参数的字节数。 一篇文章from vckbase __stdcall和_cdecl (xulion发表于2001-8-21 10:28:16) [精彩文章] 这两个关键字看起来似乎很少和我们打交道,但是看了下面的定义(来自windef.h ),你一定会觉得惊讶: #define CALLBACK __stdcall #define WINAPI __stdcall #define WINAPIV __cdecl #define APIENTRY WINAPI #define APIPRIVATE __stdcall #define PASCAL __stdcall #define cdecl _cdecl #ifndef CDECL #define CDECL _cdecl #endif 几乎我们写的每一个WINDOWS API函数都是__stdcall类型的,为什么?? 首先,我们谈一下两者之间的区别: WINDOWS的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数 调用完成后,栈需要清除,这里就是问题的关键,如何清除?? 如果我们的函数使用了_cdecl,那么栈的清除工作是由调用者,用COM的术语来讲 就是客户来完成的。这样带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同 ,那么调用者能否正常的完成清除工作呢?答案是不能。 如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨 (开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。 那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变 的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行 ,因此,这种情况我们只能使用_cdecl。 到这里我们有一个结论,如果你的程序中没有涉及可变参数,最好使用__stdcal l关键字
函数参数入栈的方式
---------------------------------------------------------------
在函数调用过程中,会使用堆栈,这三个表示不同的堆栈调用方式和释放方式。
比如说__cdecl,它是标准的c方法的堆栈调用方式,就是在函数调用时的参数压入堆栈是与函数的声明顺序相反的,其它两个可以看MSDN,不过这个对我们编程没有太大的作用
---------------------------------------------------------------
调用约定
调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。MFC支持以下调用约定:
_cdecl
按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于"C"函数或者变量,修饰名是在函数名前加下划线。对于"C++"函数,有所不同。
如函数void test(void)的修饰名是_test;对于不属于一个类的"C++"全局函数,修饰名是?test@@ZAXXZ。
这是MFC缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。
_stdcall
按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于"C"函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号"@"及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。对于"C++"函数,则有所不同。
所有的Win32 API函数都遵循该约定。
_fastcall
头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于"C"函数或者变量,修饰名以"@"为前缀,然后是函数名,接着是符号"@"及参数的字节数,如函数int func(int a, double b)的修饰名是@func@12。对于"C++"函数,有所不同。
未来的编译器可能使用不同的寄存器来存放参数。
相关文章推荐
- 转自Master HaKu 的C#调用C++写的Dll时的运行时错误解决
- 操作系统设置不当也会出现“该字符串未被识别有效的DateTime”的错误
- JQuery 模板与 css 设置不当造成 jQuery Ui 不能正常显示
- 设置打印机 提示 功能地址 造成了一个保护错误
- .NET调用Windows API隐藏控制台程序运行的窗口,并设置开机自启动
- 在运行rcnn中,调用caffe编译好的matlab接口时,遇到 libmkl_rt.so和libcudart.so.5.5错误
- asp.net运行提示未将对象引用设置到对象的实例错误解决方法
- easyui 弹出框调用外部js函数 提示“Microsoft JScript 运行时错误: 缺少对象”
- 运行时错误 说明: 服务器上出现应用程序错误。此应用程序的当前自定义错误设置禁止远程查看应用程序错误的
- [请教]安卓开发中因布局资源文件调用不当造成的StackOverFlowError有何深层原因?
- SSIS包部署错误之运行环境设置
- JavaScript在IE下设置innerHTML时出现"未知的运行时错误"
- foobar2000设置不当造成声音有噪音.
- jquery mobile在pc浏览器上设置min-height造成的错误
- [备忘]IIS 7.5运行.aspx出现“由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面。”错误解决方法
- vs2010+cryplib.lib出现错误,是运行库设置的问题
- cuDNN兼容性问题造成的caffe/mnist,py-faster-rcnn/demo运行结果错误
- 直接运行java类来调用webservce接口时发生错误
- 操作系统设置不当也会出现“该字符串未被识别有效的DateTime”的错误