一、程序的真正入口
作为一个程序员,我们都知道,一个程序要能够执行,必须有一个入口函数。对于C/C++编程人员来说,当然是main啦(这里我们就不考虑java、c#等更高级语言的入口函数啦)。您真的如此确信吗?被这么问了一下,是否慌了呢?如果你依然镇定,不外乎两种情况。一,你已经知道程序的真正入口了(高手啊);二,你还执着于main呢。如果你是第二种的话,我劝你还是放低心态,虚心接受好了。
为什么,我们会怀疑程序的真正入口(这里,再次强调C\C++)是否一定是main呢。我们知道,当编写一个C++程序时,有可能会生成一些全局和静态对象,而这些对象又必须在主函数被执行之前够造(因为在主函数-即main中,可能会使用这些对象)。于是,这个问题就产生啦,由谁构造这些对象?显然,main没有如此神通,因为它没有显示来做这些工作。这时候,你应该得树立一种观念,如果我程序无法做的,必然由操作系统来完成。的确,从某种意义上来说,是操作系统的功劳啊。
那让我们来看看一个程序从启动到执行的过程吧。
首先,加载器加载程序,查看执行体映像的头,查找/SUBSYSTEM开关的值(这个开关值,是在编译链接时插入到exe文件中的)。如果值是Console,则会创建一个新的控制台窗口(如果不是在命令行中启动程序的话);反之,如果是Windows,那么系统不会创建窗口,而是交由程序自己去做。
其次,os调用嵌入执行体的启动函数来完成初始化工作(前面已经说了,为什么会有这个函数的。。)。由于有Unicode版本和ANSI版本之分,所以,C/C++运行库在链接时使用-entry选项来设定一个C\C++运行时启动函数。
具体的启动函数对应的UNICODE和ANSI版本如下:
应用程序类型 | 入口函数 | 启动函数 |
ANSI----Console | _tmain(Main) | mainCRTStartup |
UNICODE-Console | _tmain(wMain) | wMainCRTStartup |
ANSI-GUI | _tWinMain(WinMain) | WinMainCRTStartup |
UNICODE-GUI | _tWinMain(wWinMain) | wWinMainCRTStartup |
使用的时候,根据上述对应的情况,很容易分辨出来的。
二、启动函数到底做了什么
- 获取指向新进程的完整命令行的一个指针
- 获取指向新进程的环境变量的一个指针
- 初始化C/C++运行库的全局变量。
- 初始化C运行库内存分配函数
- 调用所有全局和静态C++类对象的构造函数
好了,就谈到这里了,如果有疑问,请给我留言。。。。。