Process environment,本章讲的主要就是一个程序在什么样的一个环境下执行以及怎样执行嘛!
好,那从一个小小的main函数看起,一点点把它壮大:
#include <stdio.h> main() { printf(hello, world\n); }那么就从这个简单main开始吧。发现它的问题了吧?对第一眼注意的就是,函数没有返回值;可以说,函数结束的时候没有终止状态,或者说它的终止状态没有定义。远古时期人们会这样写,当然现在我们不这么写,那么返回什么呢?void?我记得坑坑的谭浩强老师(恕我不敬,其实对前辈本该尊敬的)经常这样写:void main()。可是,真的对吗?
不对啊,都不对啊,只有返回值int是正规大学毕业的啊,其它都是野鸡大学毕业的啊!所以,以后我们就定死了,main只有如下两种形式:
int main(/*void*/) { ... } int main(int argc, char *argv[]) { ... }但是,有人会问,为什么返回void会工作呢?其实你返回char,char*,long它都照跑不误,因为编译器它会尽量提高容错性来保证程序可以执行,而linker并不关心返回什么,它只关注main这个符号(或者说是_main),把它链接到可执行就够了。所以说,像void这类野鸡大学毕业生也就勉强毕业了。但如果严格一些,编译的时候 -Wall,很容易就会看到warning提示返回值是int。所以,我们就把程序改成下面的形式吧!
#include <stdio.h> int main() { printf("hello, world\n"); exit(0); }
那么又有人问啦:“咦?以前不是return 0吗,这怎么又成exit(0)了?”其实对于main来说,exit(0)和return 0是相同的。下面看一幅图来了解一个C程序的启动和终止:
来,看图。从exec开始看起:首先,内核启动一个程序的唯一方法就是调用one of exec functions。好啦,调用exec进入启动例程,这个启动例程是干啥的呢,执行一些初始化工作(比如说,把argc和argv传给main),然后call main。main function和user function之间的执行就不细说了,我们来看这个进程的终止是如何终止的。Normal termination(正常终止,注意不是3种abnormal termination异常终止)有5种:
(1)从main返回 (2)调用exit (3)调用_exit或_Exit (4)最后一个线程从start-up routine返回 (5)从最后一个线程调用pthread_exit;
我们回到前面的问题:return 0和exit(0)为什么是一样的。从图中看return 0就相当于在start-up routine中调用exit(main(argc, argv)),转向中间的exit函数;而exit(0)直接转向中间的exit函数,完全一样。接下来,exit执行右边的exit handler(终止处理程序)、standard I/O clearup(关闭所有打开的stream),然后通过_exit或_Exit返回到kernel中。这也可以看出exit函数和_exit,_Exit的区别,当然是exit函数多了清理善后工作嘛!对于一个进程,自愿终止地唯一方法是显示(直接调)或者隐式(通过exit调)地调用_exit或_Exit,不自愿终止的话,那就是abnormal termination啦:
(1)调用abort (2)接到一个信号 (3)最后一个线程对取消请求做出响应。
好啦,这就是一个程序怎样开始和执行的,很清楚了吧!