今天重读《windows程序设计 第五版》(作者:Charles Petzold) 时,WINAPI 被定义为__stdcall,一回想发现忘记了__stdcall的集体含义。于是查阅下相关资料。
学习过汇编的童鞋都知道,函数调用要用到stack(栈:一种后进先出的线性结构)。先简单回忆下函数的调用过程(以X86结构为例):
1.将函数的参数按照从右往左的顺序依次压入stack(栈)中。
2.将当前IP寄存器(调用者当前指令地址(从com角度来说叫客户的当前的客户指令地址))的值压入stack(栈)中,将IP寄存值改变为被调用函数的地址。
3.将被调用函数的局部变量压入stack(栈)中。
4.将被调用函数的局部变量从stack(栈)中弹出。
5.将压入栈的调用者当前指令地址+1存入IP寄存器中。
6.将EAX寄存器(一般用EAX保存函数的返回值)中的值存入被调用这的局部变量(或者全局变量中)。
7.将函数的参数从stack(栈)中弹出。
__stdcall、__cdecl、__fastcall都是函数调用的协议(约束条件)。
1.__stdcall可以写成_stdcall,参数采用从右至左边入栈顺序,由被调用函数本身将函数的参数从stack(栈)中弹出。
2.__cdecl可以写成_cdecl,参数采用从右至左的顺序的入栈顺序,由函数的调用者将函数的参数从stack(栈)中弹出,一般用于变长参数的函数例如:printf。因为被调用函数本身并不知道参数的个数,无法自身清楚堆栈。
3.__fastcall可以写成_fastcall,将函数最左边的两个不超过2个双字节(DWORD)参数存入ECX和EDX两个寄存器中,其他参数仍按从右到左的顺序压入栈中。一般用于效率要求较高的场合。