CALLBACK,__stdcall与__cdecl
CALLBACK == WINAPI ==__stdcall
实际上就是一种调用模式,就是约定由调用函数来自行解决压栈参数,同 pascal 调用。回调函数只能是类的静态成员函数或是类外定义的全局函数
#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
VC中主要有两种函数调用方式:
- 一种是__stdcall;
- 另一种是__cdecl;
- 还有第三种 naked(自己编汇编控制堆栈)。
函数的调用方式有两种:一种是PASCAL调用方式,另一种是C调用方式 。
- 使用PASCAL调用方式,被调函数在返回到调用者之前将参数从栈中删除。
- 使用C调用方式,参数的删除是调用者完成的 。
WinMain函数是由系统调用的,Windows系统规定由系统调用的函数都遵守 PASCAL调用方式 。 但是VC中函数的缺省调用方式是__cdecl,也就是C调用方式 。 在Windows编程中将遇到很多声明修饰符,如CALLBACK,WINAPI,PASCAL这些在 IntelCPU的计算机上都是__stdcall。几乎我们写的每一个WINDOWS API函数都是__stdcall类型的,为什么?首先,我们谈一下两者之间的区别:
__cdecl 和 __stdcall 的区别
windows的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈需要执行清除操作,这里就是问题的关键,如何清除?
如果我们的函数使用了_cdecl,那么栈的清除工作是由调用者,用COM的术语来讲就是客户来完成的。这样就带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。
如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨(开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。
那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行,因此,这种情况我们只能使用_cdecl。
到这里我们有一个结论,如果你的程序中没有涉及可变参数,最好使用__stdcall关键字。
CALLBACK 关键字
- CALLBACK函数也称为回调函数,是由你自己来设计,但是供windows调用的。如果你写过SDK程序,就该知道WindowProc函数,它是你自己写的,什么消息怎么处理,但是在程序中你并没有去调用这个函数,因为不需要你自己调用,到了该调用的时候windows自然会去调用。如果你的函数不是回调函数,就不要用CALLBACK或者_cdecl来修饰。
- 如果你写回调函数,而且它的参数所占的字节是不可变的,那么就用CALLBACK(大部分是这种情况),如果参数可能会变,那么就用_cdecl 。
注释:
- 所谓的回调函数,就是说,当某一个事件发生时,系统会根据你给出的函数指针来调用你定义的这个回调函数,这是系统提供的一种和用户通讯的方法。他通过调用用户自定义的函数来给用户提供一个处理消息或事件的机制。
- 回调函数并非Windows特有,只要象C/C++这样支持函数指针的语言都有回调函数的概念,它实际上是向被调用函数传一个你的函数地址,然后被调用函数向通过你传入的函数地址来调用你的函数。比如你做了一个遍历树的函数,但你不知遍历者将对各节点做何种处理时,你就可以在这个遍历函数中加一个函数地址的参数,这样调用者在遍历该树时就可以做各种有意义的工作了:比如打印各节点数据、汇总所有节点之类。
- 回调函数(CallBack Function)在windows编程中用到时,是由windows操作系统直接调用的,一般是在windows编程中的对各种事件的响应。在VC编程中不再采用回调函数了,而是采用了begin_messagemap,end_messagemap,它的作用和windows编程中的回调函数(CallBack Function)是一样的。
- 回调函数(CallBack Function)就是函数指针的调用,看看关于函数指针的用法,了解了函数指针也就了解了CALLBACK。设计一个函数接口的参数是某一函数的指针,在设计的函数中调用该函数指针,那么该指针指向的函数就是callback functioin。回调函数是由你来编写其功能实现,由Windows操作系统调用的函数。