据我所知,只有 caller-clean-stack 约定可以使用可变参数。
顺便说一句,WinApi StringCchPrintfW 是这样声明的。(我删除了 SAL)
__inline HRESULT __stdcall
StringCchPrintfW (
STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat, ...
);
stdcall 也可以有可变参数吗?
据我所知,只有 caller-clean-stack 约定可以使用可变参数。
顺便说一句,WinApi StringCchPrintfW 是这样声明的。(我删除了 SAL)
__inline HRESULT __stdcall
StringCchPrintfW (
STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat, ...
);
stdcall 也可以有可变参数吗?
不,stdcall调用约定让被调用者清理堆栈。由于被调用者正在清理堆栈,因此它无法在编译时知道要弹出多少,因此它不能有可变参数。
为了获得可变数量的函数参数,您需要使用cdecl,它让调用者清理堆栈。所有这些编译器都用于确定传递了多少参数,并且由于调用者正在清理堆栈,因此它还知道当函数调用返回时要从堆栈中弹出多少。
在上面提到的情况下,函数被声明为 use __stdcall
,如前所述,它不支持变量参数。在这种情况下,编译器决定忽略定义的调用约定并恢复为__cdecl
. 上面提到的stdcall的描述中提到了这种行为。我引用:
被调用者清理堆栈,因此编译器生成可变参数函数 __cdecl。
如果以下代码被编译并且对函数的调用被反汇编,则可以观察到这一点。
int __stdcall Bar(int a, int b, ...)
{
return b * a;
}
生成的代码将被视为__cdecl
. 至于这样定义的原因,我不知道。