6.1 main函数

        C程序总是从main函数开始执行。main函数的原型是:

int main(int argc, char *argv[]) 

6.2 进程终止

有五种方式使进程终止:

(1)正常终止:

        (a)从main返回。

        (b)调用exit。

        (c)调用_exit。

(2)异常终止:

        (a)调用abort

        (b)由一个信号终止

6.2.1 exit和_exit函数

        exit和_exit函数用于正常终止一个程序: _exit立即进入内核,exit则先执行一些清除处理 (包括调用执行各终止处理程序,关闭所有标准I / O流等),然后进入内核。

#include <stdlib.h>
void exit(int status) ;


#include <unistd.h>
void _exit (int status) ;

exit和_exit都带一个整型参数,称之为终止状态(exit status)。大多数UNIX shell都提供检查一个进程终止状态的方法。如果 ( a )若调用这些函数时不带终止状态,或 ( b ) main执行了一个无返回值的return语句,或( c ) main执行隐式返回,则该进程的终止状态是末定义的。

6.2.2 atexit函数

        一个进程可以登记多至 32个函数,这些函数将由exit自动调用。我们 称这些函数为终止处理程序(exit handler),并用atexit函数来登记这些函数。

#include <stdlib.h>

//返回:若成功则为0,若出错则为非0
int atexit(void (*func) (void) ) ;

其中,atexit的参数是一个函数地址,当调用此函数时无需向它传送任何参数,也不期望它返回一个值。 exit以登记这些函数的相反顺序调用它们。同一函数如若登记多次,则也被调用多次。

        exit首先调用各终止处理程序,然后按需多次调用fclose,关闭所有打开流。下图中显示了一个C程序是如何起动的,以及它终止的各种方式。

        内核使程序执行的唯一方法是调用一个exec函数。进程自愿终止的唯一方法是显式或隐式地(调用exit )调用_exit。进程也可非自愿地由一个信号使其终止。

6.3 命令行参数

        当执行一个程序时,调用exec的进程可将命令行参数传递给该新程序。

6.4 环境表

        每个程序都接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的字符串的地址。全局变量environ则包含了该指针数组的地址。

extern char **environ;

例如:如果该环境包含五个字符串,那么它看起来可能如下图中所示。

6 进程的环境-LMLPHP

其中,每个字符串的结束处都有一个null字符。我们称environ为环境指针,指针数组为环境表, 其中各指针指向的字符串为环境字符串。

6.5 C程序的存储空间布局

C程序一直由下列几部分组成:

  • 正文段(代码段)。这是由CPU执行的机器指令部分。通常,正文段是可共享的,所以即使是经常执行的程序(如文本编辑程序、C编译程序、shell等)在存储器中也只需有一个副本,另外,正文段常常是只读的,以防止程序由于意外事故而修改其自身的指令。
  • 初始化数据段。通常将此段称为数据段,它包含了程序中需赋初值的变量。例如, C程序中任何函数之外的说明。
  • 非初始化数据段。通常将此段称为 bss段,这一名称来源于早期汇编程序的一个操作符, 意思是“block started by symbol(由符号开始的块)”,在程序开始执行之前,内核将此段初始化为0。函数外的说明。
  • 栈。自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次函数调用时, 其返回地址、以及调用者的环境信息(例如某些机器寄存器)都存放在栈中。然后,新被调用的函数在栈上为其自动和临时变量分配存储空间。通过以这种方式使用栈, C函数可以递归调用。
  • 堆。通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于非初始化数据段顶和栈底之间。

6 进程的环境-LMLPHP

 6.6 存储器分配

三个用于存储空间动态分配的函数。

(1)malloc。分配指定字节数的存储区。此存储区中的初始值不确定。

(2)calloc。为指定长度的对象,分配能容纳其指定个数的存储空间。该空间中的每一位 (bit)都初始化为0。

(3)realloc。更改以前分配区的长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定。

#include <stdlib.h>

//三个函数返回:若成功则为非空指针,若出错则为NULL
void *malloc(size_t size) ;
void *calloc(size_t nobj, size_t size) ;
void *realloc(void *ptr, size_t newsize) ;

void free(void *ptr)

6.7 环境变量

        环境字符串的形式是:name = value

        函数getenv,可以用其取环境变量值。

#include <stdlib.h>

//返回:指向与name关联的value的指针,若未找到则为NULL
char *getenv(const char *name) ;

        除了取环境变量值,有时也需要设置环境变量,或者是改变现有变量的值,或者是增加新的环境变量。

#include <stdlib.h>

//两个函数返回:若成功则为 0,若出错则为非0
int putenv(const char *str) ;
int setenv(const char *name, const char * value, int rewrite) ;

void unsetenv(const char *name) ;

这三个函数的操作是:

  • putenv取形式为name=value的字符串,将其放到环境表中。如果 name已经存在,则先删除其原来的定义。
  • setenv将name设置为value。如果在环境中name已经存在,那么( a )若rewrit e非0,则首先 删除其现存的定义;( b )若rewrite为0,则不删除其现存定义(name不设置为新的value,而且也不出错)。
  • unsetenv删除name的定义。即使不存在这种定义也不算出错。
05-11 14:56