问题描述
使用不同调用约定的关键因素是什么?有人什么时候知道在不同场合使用特定的调用约定,例如 __cdecl
或 __stdcall
或 __fastcall
.
What are the key factors on using different calling conventions? When does someone know to use specific calling conventions such as __cdecl
or __stdcall
or __fastcall
in different occasions.
示例会非常有用.
推荐答案
大多数时候您无需担心.通常您会使用 __cdecl
,但这只是因为这是 Visual C++ 中的默认值.但是,C++ 成员函数在 Visual C++ 中默认使用 __thiscall
约定
Most of the time you don't need to worry about it. Usually you'll use __cdecl
, but only because that's the default in Visual C++. C++ member functions, however, use the __thiscall
convention by default in Visual C++
当您将回调传递给 API 函数(例如 Windows API 中的那些)时,您真正需要担心调用约定的(相当常见的)情况是:
A (rather common) situation where you really have to worry about calling conventions is when you pass callbacks to API functions, like those in the 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
'd如 __stdcall
).这是必需的,因为操作系统期望 lpfnWndProc
指向 WNDPROC
,使用CALLBACK
约定.
Here, we declare MyWndProc()
as having the __stdcall
convention (CALLBACK
is #define
'd as __stdcall
). This is needed because the operating system expects that lpfnWndProc
points to a WNDPROC
, which uses the CALLBACK
convention.
几乎每个接受回调的 Windows API 函数都要求回调函数使用 __stdcall
约定,并且由于 __cdecl
通常是默认值,因此您必须明确说明(对于窗口过程,您将使用 CALLBACK
).
Just about every Windows API function that accepts a callback requires the callback functions to use the __stdcall
convention, and since __cdecl
is usually the default, you must make this explicit (you would use CALLBACK
for window procedures).
这非常重要,因为如果操作系统尝试调用非__stdcall
函数,可能会发生堆栈损坏.不幸的是足够多的人得到这个错误是 Windows将实际检查调用专门针对窗口过程的约定不匹配.
This is extremely important because stack corruption can occur if the operating system attempts to call a non-__stdcall
function. Unfortunately enough people get this wrong that Windows will actually check for calling convention mismatch specifically for window procedures.
虽然传递给 WinAPI 函数的回调函数需要 __stdcall
,但接受可变数量参数的函数必须使用 __cdecl
调用约定,因为只有调用者知道如何从堆栈中正确弹出可变数量的参数.由于 __cdecl
通常是默认值,因此您无需为接受可变数量参数的函数显式指定 __cdecl
.
While __stdcall
is required for callback functions passed to WinAPI functions, functions that accept a variable number of arguments must use the __cdecl
calling convention, because only the caller will know how to properly pop the variable number of arguments off the stack. Since __cdecl
is usually the default, you don't need to explicitly specify __cdecl
for functions that accept a variable number of arguments.
我个人还没有发现 __fastcall
的用途,尽管我确定有人有.
I personally haven't found a use for __fastcall
, although I'm sure someone has.
__clrcall
仅在您与托管代码交互时才相关.
__clrcall
is relevant only if you're interacting with managed code.
这篇关于何时使用调用约定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!