DWORD WINAPI?stdcall?

2021-03-13 00:36

阅读:750

标签:under   语言   fun   说明   fas   开发平台   define   如何   client   

网络编程实验2_(4)基于流式套接字的服务器程序设计中,创建了以下这个函数:

DWORD WINAPI ClientThread(LPVOID lpParameter)

以前我只学过类似:

int swap(int x,int y)

这样的函数,而这个函数看起来就很诡异,如何理解这个函数呢?


 

DWORD是数据类型,在这里是返回值,返回32位数据。

在visual studio中WINAPI转到定义可以看到:

#define WINAPI __stdcall 

也就是说WINAPI是一个宏,所代表的符号是__stdcall。 

WINAPI是函数调用形式,windows API函数采用__stdcall标准调用约定,即由被调用函数来清理栈中的参数,这种方式是不能实现可变参数的。 

__stdcall是函数调用约定的一种,函数调用约定主要约束了两件事:

1.参数传递顺序

2.调用堆栈由谁(调用函数或被调用函数)清理

常见的函数调用约定:stdcall cdecl fastcall thiscall naked call

__stdcall表示

1.参数从右向左压入堆栈

2.函数被调用者修改堆栈

3.函数名(在编译器这个层次)自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸

在win32应用程序里,宏APIENTRY,WINAPI,都表示_stdcall,非常常见。


摘自:

在C语言中,假设我们有这样的一个函数:int function(int a,int b)
调用时只要用result = function(1,2)这样的方式就可以使用这个函数。但是,当高级语言被编译成计算机可以识别的机器码时,有一个问题就凸现出来:在CPU中,计算机没有办法知道一个函数调用需要多少个、什么样的参数,也没有硬件可以保存这些参数。也就是说,计算机不知道怎么给这个函数传递参数,传递参数的工作必须由函数调用者和函数本身来协调。为此,计算机提供了一种被称为栈的数据结构来支持参数传递。
栈是一种先进后出的数据结构,栈有一个存储区、一个栈顶指针。栈顶指针指向堆栈中第一个可用的数据项(被称为栈顶)。用户可以在栈顶上方向栈中加入数据,这个操作被称为压栈(Push),压栈以后,栈顶自动变成新加入数据项的位置,栈顶指针也随之修改。用户也可以从堆栈中取走栈顶,称为弹出栈(pop),弹出栈后,栈顶下的一个元素变成栈顶,栈顶指针随之修改。函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据,并进行计算。函数计算结束以后,或者调用者、或者函数本身修改栈,使堆栈恢复原装。
在参数传递中,有两个很重要的问题必须得到明确说明:
当参数个数多于一个时,按照什么顺序把参数压入堆栈函数调用后,由谁来把堆栈恢复原装。在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:
stdcall,cdecl,fastcall,thiscall,naked call


 

为了深刻理解__stdcall,我查找了一些资料,参考链接如下:

C++知识回顾之__stdcall、__cdcel和__fastcall三者的区别

(这位老哥讲的很全面,但是格式有点乱。于是我稍微调整了一下格式)

__stdcall、__cdecl和__fastcall是三种函数调用协议,函数调用协议会影响函数参数的入栈方式、栈内数据的清除方式、编译器函数名的修饰规则等。

 

调用协议常用场合

__stdcall:Windows API默认的函数调用协议。

__cdecl:C/C++默认的函数调用协议。

__fastcall:适用于对性能要求较高的场合

 

函数参数入栈方式

__stdcall:函数参数由右向左入栈。

__cdecl:函数参数由右向左入栈。

__fastcall:从左开始不大于4字节的参数放入CPU的ECX和EDX寄存器,其余参数从右向左入栈。

 

栈内数据清除方式

__stdcall:函数调用结束后由被调用函数清除栈内数据。

__cdecl:函数调用结束后由函数调用者清除栈内数据。

__fastcall:函数调用结束后由被调用函数清除栈内数据。

(1)不同编译器设定的栈结构不尽相同,跨开发平台时由函数调用者清除栈内数据不可行。

(2)某些函数的参数是可变的,如printf函数,这样的函数只能由函数调用者清除栈内数据。

(3)由调用者清除栈内数据时,每次调用都包含清除栈内数据的代码,故可执行文件较大。

 

C语言编译器函数名称修饰规则

__stdcall:编译后,函数名被修饰为“_functionname@number”。

__cdecl:编译后,函数名被修饰为“_functionname”。

__fastcall:编译后,函数名给修饰为“@functionname@nmuber”。

注:“functionname”为函数名,“number”为参数字节数。

注:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。

 

C++语言编译器函数名称修饰规则

__stdcall:编译后,函数名被修饰为“?functionname@@YG******@Z”。

__cdecl:编译后,函数名被修饰为“?functionname@@YA******@Z”。

__fastcall:编译后,函数名被修饰为“?functionname@@YI******@Z”

 

注:“******”为函数返回值类型和参数类型表。

注:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。

C语言和C++语言间如果不进行特殊处理,也无法实现函数的互相调用。

 

DWORD WINAPI?stdcall?

标签:under   语言   fun   说明   fas   开发平台   define   如何   client   

原文地址:https://www.cnblogs.com/cyx-b/p/12555128.html


评论


亲,登录后才可以留言!