2008-11-18 74 views
119

我学习Win32编程,和WinMain原型的样子:什么是__stdcall?

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

我困惑,这是什么WINAPI标识符是为发现:

#define WINAPI  __stdcall 

这是什么呢?在返回类型之后,我对此感到困惑。 __stdcall是什么?返回类型和函数名称之间有什么意义时,这意味着什么?

+1

@AndrewProck的 “虚拟”在这种情况下,改变是可以的,但总的来说,你可以使用` `来解决最少6个字符的愚蠢(并且适得其反)。 – 2014-01-10 00:01:47

回答

137

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

还有一些其他的调用约定,__cdecl__thiscall__fastcall和奇妙命名为__naked__stdcall是Win32系统调用的标准调用约定。

维基百科涵盖details

它当你调用的代码之外的功能(例如操作系统API)或操作系统叫你(这里用的WinMain是这样)主要事项。如果编译器不知道正确的调用约定,那么您可能会遇到非常奇怪的崩溃,因为堆栈将无法正确管理。

+8

看到这个问题的一个非常starnge崩溃的例子http://stackoverflow.com/questions/696306/run-time-check-failure-0-loading-queryfullprocessimagename-from-kernel32-dl​​l – sharptooth 2009-04-17 04:08:14

+0

如果我没有弄错,那么这些调用约定控制编译器如何生成汇编代码。当与汇编代码进行交互时,注意调用约定以防止堆栈问题至关重要。 这里有一个很好的表格,记录一些约定:https://msdn.microsoft.com/en-us/library/984x0h58.aspx – 2015-07-24 17:03:37

31

C或C++本身没有定义这些标识符。它们是编译器扩展并代表某些调用约定。这决定了将参数放在哪里,按照什么顺序,被调用的函数将找到返回地址,依此类推。例如,__fastcall表示函数的参数通过寄存器传递。

Wikipedia Article提供了不同的调用约定的概述发现在那里。

15

的答案至今已覆盖的细节,但如果你不打算下降到组装,那么所有你必须知道的是,无论是主叫用户和被叫必须使用相同的调用约定,否则你”会得到很难找到的错误。

9

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

4

__stdcall用于将函数参数放入堆栈。 完成该功能后,它会自动解除分配内存。 这用于固定参数。

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

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

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

1

我以前从来没有使用这个直到今天。因为在我的代码中,我使用的是多线程,而我使用的多线程API是windows one(_beginthreadex)。

要启动线程:

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

的ExecuteCommand函数MUST使用方法签名的__stdcall关键字,以便beginthreadex称之为:

unsigned int __stdcall Scene::ExecuteCommand(void* command) 
{ 
    return system(static_cast<char*>(command)); 
}