main函数调用、进程终止以及命令行参数和环境表http://www.tuicool.com/articles/FNnMNr
2015-09-21 21:26
851 查看
http://blog.csdn.net/to_be_it_1/article/details/25789429
主题 进程
(一)main函数调用
main函数作为程序运行时的入口函数,它是如何被调用的呢?首先必须清楚一点,main函数也是一个函数,它只有被调用才能够执行。其实,在执行可执行程序时,在调用main函数之前,内核会先调用一个特殊的启动例程,将此启动例程作为可执行程序的起始地址。启动例程是如何作为可执行程序的起始地址的?这是由链接编译器设置的,而链接编译器则是由C编译器(如gcc编译器)调用的。启动例程作为可执行程序的起始地址主要做哪些工作呢?启动例程从内核取得命令行参数和环境变量值,以此来为main函数的调用做准备。
(二)命令行参数
当执行一个程序时,调用exec的进程可以将命令行参数传递给该程序。示例如下:
编译测试结果:./a.out fdj fda li
(三)环境表
每个程序都会接收到一张环境表。与上面的命令行参数一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的C字符串的地址。全局变量environ则包含了该指针数组的地址。
从表中可以看出,每个字符串的结尾处都显示地有一个null字符。称environ为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串。通常用getenv和putenv函数来访问特定的环境变量,而不是environ变量。但如果要查看整个环境,则必须使用environ指针。
#include <stdlib.h>
char *getenv(const char *name); // 返回值:指向与name关联的value指针,若未找到则返回NULL
int putenv(char *string); // 返回值:若成功则返回0, 若出错则返回非0值
int setenv(const char *name, const char *value, int overwrite);
int unsetenv(const char *name);
说明如下:
1、putenv取形式为“name=value”(等号两边不要留空格)的字符串,将其放到环境表中。如果name已经存在,则先删除其原来的定义。
2、setenv将name设置为value。如果在环境中name已经存在,那么a:若rewite非0,则首先删除其现有定义;b:若rewrite为0,则不删除其现有定义(name不设置为新的value,而且不出错)。
3、unsetenv删除name的定义。即使不存在这种定义也不出错。
示例代码如下:
程序测试结果:gcc envdemo.c
(四)进程终止
既然一个程序又开始,就一定有终止。有8种方式使进程终止,其中5种为正常终止:从main返回、调用exit、调用_exit或_Exit、最后一个线程从其启动例程返回、最后一个线程调用pthread_exit;3种异常终止方式:调用abort、接到一个信号并终止、最后一个线程对取消请求做出响应。
1、exit类函数。有三个函数用于正常终止一个程序:_exit和_Exit立即进入内核,exit则先执行一些清理处理(包括调用执行各类终止处理程序,关闭所有标准I/O流等),然后进入内核。
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
2、atexit函数。一个进程可以登记多达32个函数,这些函数将由exit自动调用。我们称这些函数为终止处理程序,并调用atexit函数来登记这些函数。
#include <stdlib.h>
int atexit(void (*func)(void)); // 若成功则返回0, 若出错则返回非0值
atexit参数是一个函数地址,当调用此函数时无需向他传送任何参数,也不期望它返回一个值。exit调用这些函数的顺序与它们登记时的顺序相反。同一函数如若登记多次,则也返回多次。
示例代码:
编译测试结果:
主题 进程
(一)main函数调用
main函数作为程序运行时的入口函数,它是如何被调用的呢?首先必须清楚一点,main函数也是一个函数,它只有被调用才能够执行。其实,在执行可执行程序时,在调用main函数之前,内核会先调用一个特殊的启动例程,将此启动例程作为可执行程序的起始地址。启动例程是如何作为可执行程序的起始地址的?这是由链接编译器设置的,而链接编译器则是由C编译器(如gcc编译器)调用的。启动例程作为可执行程序的起始地址主要做哪些工作呢?启动例程从内核取得命令行参数和环境变量值,以此来为main函数的调用做准备。
(二)命令行参数
当执行一个程序时,调用exec的进程可以将命令行参数传递给该程序。示例如下:
/* *File Name : argdemo.c *Author : libing *Mail : libing1209@126.com *Function : show the arguments you input */ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; for(i = 0; i < argc; i++){ printf("argv[i] = %s.\n", argv[i]); } exit(0); }
编译测试结果:./a.out fdj fda li
argv[i] = ./a.out. argv[i] = fdj. argv[i] = fda. argv[i] = li.
(三)环境表
每个程序都会接收到一张环境表。与上面的命令行参数一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的C字符串的地址。全局变量environ则包含了该指针数组的地址。
从表中可以看出,每个字符串的结尾处都显示地有一个null字符。称environ为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串。通常用getenv和putenv函数来访问特定的环境变量,而不是environ变量。但如果要查看整个环境,则必须使用environ指针。
#include <stdlib.h>
char *getenv(const char *name); // 返回值:指向与name关联的value指针,若未找到则返回NULL
int putenv(char *string); // 返回值:若成功则返回0, 若出错则返回非0值
int setenv(const char *name, const char *value, int overwrite);
int unsetenv(const char *name);
说明如下:
1、putenv取形式为“name=value”(等号两边不要留空格)的字符串,将其放到环境表中。如果name已经存在,则先删除其原来的定义。
2、setenv将name设置为value。如果在环境中name已经存在,那么a:若rewite非0,则首先删除其现有定义;b:若rewrite为0,则不删除其现有定义(name不设置为新的value,而且不出错)。
3、unsetenv删除name的定义。即使不存在这种定义也不出错。
示例代码如下:
/* *File Name : envdemo.c *Author : libing *Mail : libing1209@126.com *Function : test some function of env */ #include "apue.h" #include <stdlib.h> int main(int argc, char *argv[]) { char *value; int i; value = getenv("PWD"); printf("%s\n", value); if(!getenv("libing")){ printf("can't find env libing.\n"); } putenv("libing=libing1209@126.com"); value = getenv("libing"); printf("%s\n", value); unsetenv("libing"); if(getenv("libing") == NULL) printf("can't find env libing.\n"); exit(0); }
程序测试结果:gcc envdemo.c
/work/tmp/apue/chapter7 can't find env libing. libing1209@126.com can't find env libing.
(四)进程终止
既然一个程序又开始,就一定有终止。有8种方式使进程终止,其中5种为正常终止:从main返回、调用exit、调用_exit或_Exit、最后一个线程从其启动例程返回、最后一个线程调用pthread_exit;3种异常终止方式:调用abort、接到一个信号并终止、最后一个线程对取消请求做出响应。
1、exit类函数。有三个函数用于正常终止一个程序:_exit和_Exit立即进入内核,exit则先执行一些清理处理(包括调用执行各类终止处理程序,关闭所有标准I/O流等),然后进入内核。
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
2、atexit函数。一个进程可以登记多达32个函数,这些函数将由exit自动调用。我们称这些函数为终止处理程序,并调用atexit函数来登记这些函数。
#include <stdlib.h>
int atexit(void (*func)(void)); // 若成功则返回0, 若出错则返回非0值
atexit参数是一个函数地址,当调用此函数时无需向他传送任何参数,也不期望它返回一个值。exit调用这些函数的顺序与它们登记时的顺序相反。同一函数如若登记多次,则也返回多次。
示例代码:
/* *File Name : atexit.c *Author : libing *Mail : libing1209@126.com *function : test the function atexit */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> static void my_exit1(void); static void my_exit2(void); int main() { if((atexit(my_exit2)) != 0) printf("can't register my_exit2"); if((atexit(my_exit1)) != 0) printf("can't register my_exit1"); if((atexit(my_exit1)) != 0) printf("can't register my_exit1"); printf("main is done.\n"); return 0; }
编译测试结果:
main is done. first exit handler first exit handler second exit handler
相关文章推荐
- UNIX环境编程学习笔记(16)——进程管理之进程环境变量 http://www.cnblogs.com/lienhua34/p/4005367.html
- hdu5452(2015沈阳网络赛C题)
- hdu5455(2015沈阳网络赛F题)
- hdu5459(2015沈阳网络赛J题)
- 农村借贷会是网络巨头的下一个角斗场吗?
- TCP客户/服务器程序示例
- iOS9 HTTP 不能正常使用的解决办法
- 常见的HTTP状态码
- Android请求网络共通类——Hi_博客 Android App 开发笔记
- centos 7 网络配置( 网关、dns、ip地址配置)
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2015)网络赛 B Mission Impossible 6
- Linux环境变量的设置和查看方法 http://soft.chinabyte.com/os/169/11412169.shtml
- ExtJS4 Ext.onReady、Ext.define、Ext.create的区别与联系 http://blog.sina.com.cn/s/blog_48d7f92901011cfn.html
- extjs组件添加事件监听的三种方式 http://blog.sina.com.cn/s/blog_48d7f92901011cfn.html
- 2015北京网络赛题目: Fractal(打表+二分模拟)
- linux常用c函数 进程操作篇 http://blog.chinaunix.net/uid-25906157-id-3136757.html
- TCP协议:服务端和客户端demo--【J2SE】
- 进程终止函数:abort, atexit, exit, _exit, _Exit http://blog.sina.com.cn/s/blog_605f5b4f0100x3v0.html
- hdu 5446(2015长春网络赛J题 Lucas定理+中国剩余定理)
- hdu 5438 Ponds(长春网络赛 拓扑+bfs)