进程环境

来源:互联网 发布:ubuntu安装openssh 编辑:程序博客网 时间:2024/05/17 07:16

1.     首先通过下图了解C程序是如何启动和终止的。


1.C程序的启动

当内核执行C程序时,(使用一个exec函数),在调用main之前先调用一个特殊的启动例程。启动例程从内核取得命令行参数和环境变量值,为调用main函数做还安排。

 

2.进程终止的方式

正常终止

(1).从main返回。

(2).调用exit

(3).调用_exit(#include<unistd.h>)或_Exit(#include<stdlib.h>)

(4).最后一个线程从其启动例程返回

(5).最后一个线程调用pthread_exit()

异常终止

(6).调用abort()

(7).接到一个信号并终止(SIGKILL)

(8).最后一个线程对取消请求做出响应(pthread_cancle)

 

exit函数

#include <stdlib.h>

(1).void exit(int status);

(2).void _Exit(int status);

#include <unistd.h>

(3).void _exit(int status);

 

_exit和_Exit立即进入内核

exit先执行一些清理处理(刷新缓冲区或关闭文件)然后调用上述两个函数进入内核

exit:#include <stdio.h>#include <stdlib.h>Int main(void){printf(“I can be showing on the terminal by exit()”);//注意这里没有以’\n’来结尾exit(0);}

在这里终端打印了printf输出语句。

_exit:#include <stdio.h>#include <unistd.h>int main(void){printf("i can be showing on the terminal by exit()");_exit(0);}_Exit:#include <stdio.h>#include <stdlib.h>int main(void){printf("i can be showing on the terminal by exit()");_Exit(0);}
这两种情况都没有打印出printf语句。这是因为_exit()和_Exit直接进入内核,不会考虑IO缓冲区是否还有数据。

3.atexit函数:

头文件:#include <stdlib.h>

函数声明:int atexit(void (*function)(void));

函数说明: atexit用来登记一个程序正常结束前调用的函数(终止处理程序)。当程序通过调

用 exit()或从 main 中返回时,参数 function 所指定的函数会先被调用,然后才真正由 exit()结束程序。

返回值:如果执行成功则返回0,否则返回-1.设置errno

其中atexit函数的参数是一个函数指针,此函数不需要任何参数,也没有返回值。

_exit调用这些函数的顺序与他们登记时候的顺序相反。同一函数如果登记多次,则也会被调用多次。

下面是一个atexit的例子:

#include <stdio.h>#include <stdlib.h>static void exit_1(void);static void exit_2(void);int main(void){if(atexit(exit_2) != 0){printf("cant register exit_2\n");}if(atexit(exit_1) != 0){printf("cant register exit_1\n");}if(atexit(exit_1) != 0){printf("cant register exit_1\n");}printf("main is done\n");return 0;}static void exit_1(void){printf("first exit_1 handle\n");}static void exit_2(void){printf("second exit_2 handle\n");}



4.命令行参数

echo命令的简单实现:

#include <stdio.h>#include <stdlib.h>int main(int argc,char *argv[]){int i;/*for(i = 1; i < argc; i++){printf("%s\t",argv[i]);}*/for(i = 1; argv[i] != NULL; i++){printf("%s\t",argv[i]);}putchar('\n');exit(0);}

argv[argc]是一个空指针,所以可以将参数处理循环改写为

for(i = 1; argv[i] != NULL; i++)


5.环境表:

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

extern char **environ;



6.C程序的存储布局

(1).正文段(代码段):这是CPU执行的机器指令的部分,也就是存储程序代码的区域。

(2).初始化数据段(数据段):包含了程序中需明确赋值的变量。一般是全局变量

(3).非初始化数据段:在程序开始之前,内核将此段中的变量初始化为0或空指针。一般是全局变量。

(4).栈:自动变量(传递给函数的参数(副本机制),返回值(副本机制),函数内部声明的局部变量)。

(5).堆:通常在堆中进行动态存储分配。一般由malloc/calloc/realloc函数开辟的内存区域。

 




7.存储器的分配

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

(1).malloc 分配指定的字节数的存储区,此存储区没有被初始化。

(2).calloc 为指定数量具有指定长度的对象分配存储空间。该区域每一位都被初始化为0.

(3).realloc: 更新以前分配区的长度。需要注意的是,realloc的最后一个参数指定的长度是存储区的新长度,而不是新,旧存储区的长度之差。

更详细的解释在APUE2-7.8



8.setjmp和longjmp函数

这两个函数处理发生在深层嵌套函数调用中的出错情况很有用。

这两个函数类似于非局部的goto,它们在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。(从某个函数跳转到另一个函数)。



Setjmp参数env(传出参数)的类型是一个特殊类型jmp_buf,某种形式的数组。其中存放了在调用longjmp时能够回复栈状态的所有信息。因为需要在不同的函数中引用env变量,所以一般将env变量定义为全局变量。

Longjmp 的第一个参数是在调用setjmp时所用的env,第二个参数将成为setjmp函数的返回值为非0值。

 


0 0
原创粉丝点击