何时使用调用约定

问题描述 投票:0回答:1

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

__cdecl
__stdcall
__fastcall

示例将非常感激。

visual-c++ calling-convention
1个回答
16
投票

大多数时候您无需担心。通常您会使用

__cdecl
,但这只是因为这是 Visual C++ 中的默认设置。然而,C++ 成员函数在 Visual C++ 中默认使用
__thiscall
约定

您真正需要担心调用约定的一种(相当常见)情况是,当您将回调传递给 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
d 为
__stdcall
)。这是必需的,因为操作系统期望
lpfnWndProc
指向
WNDPROC
使用
CALLBACK
约定

几乎每个接受回调的 Windows API 函数都要求回调函数使用

__stdcall
约定,并且由于
__cdecl
通常是默认值,因此您必须明确说明这一点(对于窗口过程,您将使用
CALLBACK
)。

这非常重要,因为如果操作系统尝试调用非

__stdcall
函数,可能会发生堆栈损坏。不幸的是,很多人都犯了这个错误,Windows 实际上会专门检查窗口过程的调用约定是否不匹配。

虽然传递给 WinAPI 函数的回调函数需要

__stdcall

,但接受可变数量参数的函数必须使用 
__cdecl
 调用约定,因为只有调用者知道如何正确地将可变数量的参数弹出堆栈。由于 
__cdecl
 通常是默认值,因此您无需为接受可变数量参数的函数显式指定 
__cdecl

我个人还没有发现

__fastcall

 的用途,尽管我确信有人已经找到了。

__clrcall

 仅当您与托管代码交互时才相关。

© www.soinside.com 2019 - 2024. All rights reserved.