一 进程终止:
⼀个进程可以登记若⼲个(具体⾃⼰验证⼀下)个函数,这些函数由exit⾃动调⽤,这些函数被称为终⽌处理函数, atexit函数可以登记这些函数。 exit调⽤终⽌处理函数的顺序和atexit登记的顺序相反,如果⼀个函数被多次登记,也会被多次调⽤。
以下函数的调用时程序异常或者正常终止:
进程终⽌的⽅式有8种,前5种为正常终⽌,后三种为异常终⽌:
1 从main函数返回;
2 调⽤exit函数;
3 调⽤_exit或_Exit;
4 最后⼀个线程从启动例程返回;
5 最后⼀个线程调⽤pthread_exit;
6 调⽤abort函数;
7 接到⼀个信号并终⽌;
8 最后⼀个线程对取消请求做出响应。
exit()和_exit()以及_Exit()函数的本质区别是是否立即进入内核,_exit()以及_Exit()函数都是在调用后立即进入内核,而不会执行一些清理处理,但是exit()则会执行一些清理处理,这也是为什么会存在atexit()函数的原因,因为exit()函数需要执行清理处理,需要执行一系列的操作,这些终止处理函数实际上就是完成各种所谓的清除操作的实际执行体。
我们来验证下atexit的执行顺序:
#include <stdio.h>
#include <stdlib.h>
void func1(){
printf("func1");
}
void func2(){
printf("func2");
}
void func3(){
printf("func3");
}
int main(){
atexit(func1);
atexit(func2);
atexit(func3);
return 1;
}
执行结果:可以看到atexit函数的调用顺序和登记顺序是相反的
func3
func2
func1
二 命令行参数和环境表
在执行一个程序的时候,命令行参数可以传递给程序,方法就是通过main函数中的argc和argv参数
int main(int argc,char *argv[]){
for(int j=0;j<argc;j++){
printf("argc[%d]:%s ",j,argv[j]);
}
}
执行结果。第一个参数就是具体的命令行。
root@zhf-maple:/home/zhf/c_prj# ./chapter7 arg1 arg2 arg3
argc[0]:./chapter7
argc[1]:arg1
argc[2]:arg2
argc[3]:arg3
环境表:
每个程序都会接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的C字符串的地址。全局变量environ则包含了该指针数组的地址
调用方法如下:
extern char **environ;
int main(int argc,char *argv[]){
for(int i=0;environ[i]!=NULL;i++){
printf("%s ",environ[i]);
}
return 1;
}
但是在UNIX系统中其实main函数带3个参数,其中第三个参数就是环境表地址
int main(int argc,char *argv[],char *envp[]){
for(int i=0;envp[i]!=NULL;i++){
printf("%s ",envp[i]);
}
return 1;
}
如果想查询或者设置单个的环境变量该如何操作呢,这就需要用到操作环境变量的几个函数:
char *getenv(const char *name);
函数的返回值是name=value中value字符串的地址,若未找到则返回NULL。
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存在,当rewrite非0,则首先删除其现有的定义。当rewrite为0,则不删除其现有的定义(name不设置为新的value,而且也不出错);
unsetenv删除name的定义。即使name不存在也不出错。
来看下具体的使用方法:
通过设置name=“HOME”得到HOME的地址
void getenv_function(){
char *ret;
const char *name="HOME";
ret=getenv(name);
printf("%s",ret);
}
设置环境变量
char str[10]="sex=male";
void putenv_function(){
putenv(str);
}
setenv设置环境变量
void setenv_function(){
char name[10]="name";
char *str=(char *)malloc(20*sizeof(char));
const char *value="zhf";
memcpy(str,name,sizeof(name));
setenv(str,value,1);
}
putenv和setenv的区别:
setenv必须分配存储区,以便依据其参数创建name=value字符串。同时,putenv则无需将传送给它的参数字符串直接放到环境中。
注意:在使用putenv时,将存放在栈中的字符串作为参数传送给该函数时就会发生错误,其原因是,从当前函数返回时,其栈帧占用的存储区可能将被重用。