C程序总是从main函数开始。当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址——这是由连接编译器设置的,而连接编译器则由C编译器调用(通常是cc)。启动例程从内核取得命令行参数和环境变量值。然后调用main函数。
二、进程终止
有8种方式使进程终止,其中5种为正常终止,它们是:
(1)从main返回
(2)调用exit
(3)调用_exit或_Exit
(4)最后一个线程从启动例如程返回
(5)最后一个线程调用pthread_exit
异常终止有3种方式:
(6)调用abort
(7)接到一个信号并终止
(8)最后一个线程对取消请求做出响应
void exit(int status); void _Exit(int status); void _exit(int status);
这三个函数用于终止一个程序:_exit和_Exit立即进入内核,exit则先执行一些清理处理(执行一个标准I/O库的清理关闭操作:为所有打开流调用fclose函数,这会造成所有缓冲的输出数据都被冲洗,写到文件上),然后进入内核。
三个exit函数都带有一个整型参数,称为终止状态(参数status)。
main函数返回一整型值与用该值调用exit是等价的。于是在main函数中exit(0)等价于return (0)。
三、环境表
每个程序都接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的c字符串的地址。全局变量environ则包含了指针数组的地址:
extern **environ;
我们称environ;为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串。
环境字符串的形式通常如下:
name=value
函数getenv,可以用其取环境变量值:
char* getenv(const char* name);
返回值:指向与name关联的value的指针,若未找到则返回NULL
注意,此函数返回一个指针,它指向name=value字符串中的value。int putenv(char* str); int setenv(const char* name,const char* value,int rewrite); int unsetenv(const char* name);
- putenv取形式为name=value的字符串,将其放到环境表中。如果name已经存在,则先删除其原来的定义。
- setenv将name设置为value。如果在环境中name已经存在,那么(a)若rewrite非0,则首先删除其现有的定义;(b)若rewrite为0,则不删除其现有定义(name不设置为新的value,而且也不出错)
- unsetenv删除name的定义。即使不存在这种定义也不算出错。
四、存储器分配
void* malloc(size_t size); void* calloc(size_t n,size_t size); void* realloc(void* ptr,size_t newsize);
(1)malloc。分配指定字节数的存储区。此存储区中的初始值不确定。
(2)calloc。为指定数量具指定长度的对象分配存储空间。该空间中的每一位都初始化为0.在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针。
(3)realloc。更改以前分配区的长度(增加或减少)。当增加长度时,可能(关键是看现有存储区后面是否有足够的空间)需要将以前分配区的内容移到另一个足够大的区域,以便在尾端提供增加的存储区,而新增区域区的初始值则不确定。
注意:realloc的最后一个参数时存储区的newsize(新长度),它不是新、旧存储区长度之差。作为一个特例,若ptr是一个空指针,则realloc的功能与malloc相同,用于分配一个指定长度为newsize的存储区。