启动函数和入口函数
ʕ •ᴥ•ʔ ɔ:
1 程序的启动函数和入口函数
Windows支持两种类型的应用程序:
- GUI:图形化应用程序(图形用户界面程序)
- CUI:控制台应用程序(控制台用户界面程序)
main
、Winmain
函数被称为入口函数,入口函数被调用前,会先运行启动函数,然后由启动函数来调用入口函数。
启动函数和入口函数在多字节编码(ANSI)和Unicode编码环境下是不一样的,具体对应关系如下:
也可指定/移除链接器开关(如果移除链接器开关,程序将会自动判断子系统),VS中设置如下:
/SUBSYSTEM:WINDOWS
/SUBSYSTEM:CONSOLE
入口函数:
1 | int WINAPI _tWinMain( |
启动函数:
- 启动函数由KERNEL32.dll中的
KERNEL32
函数调用,我们无法查看KERNEL32.dll的源码。 - VC++自带C运行库的源代码,可以在
crtexe.c
中找到这4个启动函数的源代码。
2 CUI程序
调用顺序:KERNEL32
--> mainCRTStartup
--> main
。
2.1 启动函数
启动函数工作流程:
GetVersion() :获取当前运行平台的版本号。控制台程序运行在Windows模拟的DOS下,因此这里获取的版本号为MS-DOS的版本信息。
_heap_init() :用于初始化堆空间。在函数实现中使用
HeapCreate
申请堆空间,申请空间的大小由_heap_init
传递的参数决定。_sbh_heap_init
函数用于初始化堆结构信息。堆结构的说明将在第7章详细讲解。GetCommandLineA() :获取命令行参数信息的首地址。
_crtGetEnvironmentStringsA:获取环境变量信息的首地址。
_setargv() :参数分析。此函数根据
GetCommandLineA()
获取命令行参数信息的首地址并进行参数分析,将分离出的参数的个数保存在全局变量_argc
中,将分析出的每个命令行参数的首地址存放在数组中,并将这个字符指针数组的首地址保存在全局变量_argv
中。这样就得到了命令行参数的个数,以及命令行参数信息。_setenvp() :环境变量分析。此函数根据
_crtGetEnvironmentStringsA
函数获取环境变量信息的首地址并进行分析,将得到的每条环境变量字符串的首地址存放在字符指针数组中,并将这个数组的首地址存放在全局变量env
中。_cinit() :用于全局数据和浮点寄存器的初始化。全局对象和IO流等的初始化都是通过这个函数实现的。利用函数
_initterm
进行数据链初始化,这个函数由两个参数组成,类型为_PVFV*
,这是一个函数指针数组,其中保留了每个初始化函数的地址。初始化函数的类型为_PVFV
,其定义原型如下:typedef void (_cdecl *_PVFV) (void);
2.2 入口函数
1