2010-08-04 34 views
6

使用不同调用约定的关键因素是什么?什么时候有人知道在不同的场合使用特定的呼叫约定,如__cdecl__stdcall__fastcall何时使用调用约定

示例将被真正apprciated。

回答

12

大多数时候你不需要担心它。通常你会使用__cdecl,但只是因为这是Visual C++中的默认值。但是,C++成员函数在默认情况下使用Visual C++

当您将回调传递给API函数(如Windows API中的函数)时,您确实需要担心调用约定的一种(相当常见的)情况:

// CALLBACK is #define'd as __stdcall 
LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg 
    WPARAM wParam, LPARAM lParam); 
// ... 
windowClass.lpfnWndProc = &MyWndProc; 
::RegisterClass(&windowClass); 

在这里,我们声明MyWndProc()作为具有__stdcall约定(CALLBACK#define倒是如__stdcall)。这是因为操作系统期望lpfnWndProc指向WNDPROC,which uses the CALLBACK convention

几乎所有的Windows API,它接受一个回调函数需要回调函数使用__stdcall惯例,而且由于__cdecl通常是默认的,你必须更加明确,(你会使用CALLBACK的窗口过程)。

这非常重要,因为如果操作系统尝试调用非__stdcall函数,则可能会发生堆栈损坏。不幸的是,足够的人得到这个错误Windows will actually check for calling convention mismatch specifically for window procedures

虽然__stdcall需要传递给WinAPI的函数回调函数,接受的参数个数可变必须使用__cdecl调用约定,因为只有调用者将知道如何正确地弹出可变数量的参数从堆栈功能。由于__cdecl通常是默认值,因此您无需为接受可变数量参数的函数明确指定__cdecl

我个人还没有找到用于__fastcall,虽然我确定有人有。

__clrcall仅在您与托管代码进行交互时才有用。