Main函数之前
Version: 2011-10-13
Author: green-waste (at)163.com
【声明】
此文主要是摘录和整理《程序员修养》那本书中关于运行库部分相关的内容,为了简要的总结一下main函数之前都干了啥。
【正文】
多数人接触C语言的人,对main函数,应该都比较了解了。不少人,应该是,或许以为main就是程序执行的入口,或许知道main函数不是入口,但是不知道哪里是入口,又或许知道入口,但是对于main之前发生的事情,系统做了哪些事情,不是很清楚。
那么,下面这段文字,目的就是简单介绍一下,main之前到底发生了什么。
在main函数中,一般来说,你可以放心去使用很多资源了,比如:申请内存,使用系统调用,触发异常,访问I/O,使用scan/printf等输入输出等等。
之所以你可以放心使用这些资源,那么是因为有人帮你在main函数执行之前,就帮你准备好了这些东西供你使用。
到底是谁做的?答案是,运行库。不过在介绍运行库之前,先要清楚一般程序执行的过程是怎么样的。
【程序运行步骤】
一个典型的程序运行步骤大致如下:
(1) 操作系统在创建进程后,把控制权交到了程序的入口,这个入口往往是运行库的某个入口函数。
(2) 入口函数对运行库和程序运行环境进行初始化,包括堆Heap,I/O,线程。全局变量构造等等。
(3) 入口函数在完成初始化之后,调用main函数,正式执行程序主体部分。
(4) Main函数执行完毕之后,返回到入口函数,入口函数进行清理工作,包括全局变量析构、堆销毁、关闭I/O等,然后进行系统调用结束进程。
【入口函数】
从上面可以看出,其实真正所谓的程序开始部分,其实可以算是入口函数。
入口函数,也叫入口点(Entry Point),是运行库的一部分,视平台不同而有不同名字。
下表显示了不同平台下,对应的入口函数的相关内容:
表格 1 不同平台下的入口函数相关信息
平台 | 运行库 | 入口函数的名称 | 说明 |
Linux | Glibc.c | __libc_start_main | 详情参考glibc源码中libc/csu位置的源码 |
Windows | MSVC CRT的Crt0.c | mainCRTStartup | 以Microsoft Visual Studio 2003为例,代码位于VC安装目录crt/src中 |
【__libc_start_main和mainCRTStartup】
1. __libc_start_main
Glib的库源码
http://ftp.gnu.org/gnu/libc/glibc-2.14.tar.bz2
中找到的文件是:csuLibc-start.c
对应函数代码为:
STATIC int /* Result of the ‘main’ function. */ __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up; #ifndef SHARED INIT_ARGV_and_ENVIRON; /* Store the lowest stack address. This is done in ld.so if this is # ifdef HAVE_AUX_VECTOR /* Performe IREL{,A} relocations. */ /* Initialize the thread library at least a bit since the libgcc /* Set up the stack checker’s canary. */ /* Register the destructor of the dynamic linker if there is any. */ #ifndef SHARED /* Register the destructor of the program, if any. */ /* Some security at this point. Prevent starting a SUID binary where /* Call the initializer of the program, if any. */ #ifdef SHARED afct = afct->next; #ifdef SHARED #ifdef HAVE_CLEANUP_JMP_BUF int not_first_call; /* Store old info. */ /* Store the new cleanup handler info. */ /* Run the program. */ /* One less thread. Decrement the counter. If it is zero we if (! atomic_decrement_and_test (ptr)) exit (result); |
2.mainCRTStartup
此处安装的VS2005,对应的文件为:
C:Program FilesMicrosoft Visual Studio 8VCcrtsrccrt0.c
mainCRTStartup函数代码为:
__declspec(noinline) __try { /* osplatform = posvi->dwPlatformId; /* _set_osplatform(osplatform); /* if ( !_heap_init(1) ) /* initialize heap */ if( !_mtinit() ) /* initialize multi-thread */ /* Enable buffer count checking if linking against static lib */ /* __try { if ( _ioinit() < 0 ) /* initialize lowio */ /* get wide cmd line info */ /* get wide environ info */ if ( _tsetargv() < 0 ) initret = _cinit(TRUE); /* do C data initialize */ #ifdef _WINMAIN_ lpszCommandLine = _twincmdln(); if ( !managedapp ) _cexit(); } mainret = GetExceptionCode(); if ( !managedapp ) _c_exit(); } /* end of try – except */ return mainret; |
【运行库】
接下来,再简单解释解释运行库。
运行库,即运行时库(Runtime Library),而C语言的运行库,即被称为C运行库(CRT,C Runtime Language)。
最初看到这个缩写,我以为是CRT显示器呢,呵呵。
一个C语言运行库大致包含了如下功能:
(1) 启动与退出:包括入口函数及入口函数所依赖的其他函数等。
(2) 标准函数:由C语言标准规定的C语言标准库所拥有的函数实现。
(3) I/O:I/O功能的封装和实现。
(4) 堆:堆的封装和实现。
(5) 语言实现:语言中一些特殊的功能。
(6) 调试:实现调试功能的代码。
关于每一部分的详细内容,就不多说了。
【引用】
1.《程序员的自我修养 – 链接、装载与库》 俞甲子 石凡 潘爱民 著
转载请注明:在路上 » Main函数之前 v2011-10-13