1.进程终止
有八种方式使进程终止
(1)从main返回
(2)调用exit;
(3)调用_exit或者_Exit;
(4)最后一个线程从其启动历程返回
(5)最后一个线程调用pthread_exit;
异常终止方式有三种:
(6)调用abort();
(7)接到一个信号;
(8)最后一个线程对取消请求做出相应
三个函数用于正常终止一个程序:
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
其中_exit和_Exit函数立即进入内核。exit则先执行一些清理处理,再进入内核。
函数atexit
#include <stdlib.h>
int atexit(void (*func)(void));
ISO C规定,一个进程可以通过atexit()登记至多32个函数。这些函数在进程结束的时候自动的执行。
2.环境表
每个进程都有一张环境表,全局变量environ则包含了指向环境表的指针。
ISO C定义了一个函数getenv来取环境变量的值。
#include <stdlib.h>
char *getenv(const cahr *name);
除了获取环境变量,有时还需要设置环境变量。
#include <stdlib.h>
int putenv(char * str);//取形式为name=value的字符串,将其放到环境表中。如果name已经存在,则先删除其定义。
int setenv(const char *name,const char *value,int rewrite);//将name设置为value。如果在环境中name已经存在,那么(a)若rewrite非0,则首先删除其现有定义;(b)若rewrite为0,则不删除其现有定义。
int unsetenv(const char *name);//unsetenv删除name的定义。即使不存在也不出错。
3.C语言的存储空间布局
C程序一直由下列几部分组成:
(1)正文段。即CPU执行的机器指令。
(2)初始化数据段。通常称为数据段,它包含了程序中需明确地赋值的变量。
例如,C语言中任何函数之外的声明:
long max = 0;
(3)未初始化数据段。在程序开始前,内核将此段中的数据初始化为0或者空指针。
例如,函数外的声明:
long sum[1000];
(4)栈。自动变量以及每次函数调用时所需保存的信息都存储在栈中。每次函数调用时,其返回地址以及调用者的环境信息(如机器中某些寄存器的值)都保存在栈中。被调用的函数在栈上为自动和临时变量分配存储空间。
(5)堆。通常在堆中进行动态的存储分配。
下图显示了一种典型的存储空间安排方式:
4.共享库
共享库(可以理解为动态链接)使得可执行文件中不再需要包含公用的库函数。程序第一次执行或者第一次调用某个函数库时,用动态链接方法将程序与共享库函数相链接。这减少了可执行文件的长度,但增加了时间开销。
动态链接和静态链接的区别:
静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件;动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持。
静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。
5.函数setjmp,longjmp
在C语言中,goto()语句是不能跨越函数的。要实现跨越函数的跳转,要使用setjum()与longjmp()函数。
#include <setjmp.h>
int setjmp(jum_buf env);
void longjum(jmp_buf env,int val);
在希望返回的位置调用setjmp。其参数env是jmp_buf类型,这一类型能在调用longjmp时恢复栈状态的所有信息。在希望返回到setjmp位置处时,调用longjmp()即可。