165

我正在学习 Win32 编程,WinMain原型如下:

int WINAPI WinMain ( HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show )

我对这个WINAPI标识符的用途感到困惑并发现:

#define WINAPI      __stdcall

这是做什么的?我对在返回类型之后有什么东西感到困惑。是__stdcall为了什么?当返回类型和函数名之间存在某些东西时,这意味着什么?

4

8 回答 8

195

__stdcall是用于函数的调用约定。这告诉编译器适用于设置堆栈、推送参数和获取返回值的规则。

还有许多其他的调用约定,,__cdecl和奇妙的命名。 是 Win32 系统调用的标准调用约定。__thiscall__fastcall__declspec(naked)__stdcall

维基百科涵盖了细节

当您在代码之外调用函数(例如,操作系统 API)或操作系统正在调用您(如 WinMain 的情况)时,这主要是重要的。如果编译器不知道正确的调用约定,那么您可能会遇到非常奇怪的崩溃,因为堆栈将无法正确管理。

于 2008-11-18T02:18:06.080 回答
44

C 或 C++ 本身不定义这些标识符。它们是编译器扩展,代表某些调用约定。这决定了将参数放在哪里,以什么顺序,被调用函数将在哪里找到返回地址,等等。例如,__fastcall 意味着函数的参数通过寄存器传递。

维基百科文章概述了那里发现的不同调用约定。

于 2008-11-18T02:20:26.760 回答
23

到目前为止的答案已经涵盖了细节,但是如果你不打算下拉到汇编,那么你所需要知道的是调用者和被调用者都必须使用相同的调用约定,否则你会得到错误很难找到。

于 2008-11-18T02:24:57.313 回答
12

我同意到目前为止所有的答案都是正确的,但这就是原因。Microsoft 的 C 和 C++ 编译器为应用程序的 C 和 C++ 函数中的(预期)函数调用速度提供了各种调用约定。在每种情况下,调用者和被调用者必须就使用哪种调用约定达成一致。现在,Windows 本身提供了函数(API),而且这些函数已经编译好了,所以当你调用它们时,你必须遵守它们。对 Windows API 的任何调用以及来自 Windows API 的回调都必须使用 __stdcall 约定。

于 2008-11-18T02:31:24.900 回答
10

看一下:

http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

于 2009-06-30T15:02:01.800 回答
5

它与函数的调用方式有关——基本上是事物放入堆栈的顺序以及谁负责清理。

这是文档,但除非您了解第一部分,否则意义不大:http:
//msdn.microsoft.com/en-us/library/zxk0tw93.aspx

于 2008-11-18T02:19:05.593 回答
5

__stdcall 用于将函数参数放入堆栈。函数完成后,它会自动释放内存。这用于固定参数。

void __stdcall fnname ( int, int* )
{
    ...
}

int main()
{
    CreateThread ( NULL, 0, fnname, int, int*...... )
}

这里fnname有 args 它直接推入堆栈。

于 2009-04-17T04:03:38.473 回答
1

直到今天,我以前从未使用过这个。这是因为在我的代码中我使用的是多线程,而我使用的多线程 API 是 windows 之一(_beginthreadex)。

要启动线程:

_beginthreadex(NULL, 0, ExecuteCommand, currCommand, 0, 0);

ExecuteCommand 函数必须在方法签名中使用 __stdcall 关键字,以便 beginthreadex 调用它:

unsigned int __stdcall Scene::ExecuteCommand(void* command)
{
    return system(static_cast<char*>(command));
}
于 2016-05-23T03:13:35.253 回答