Linux环境编程之进程(一):main函数调用、进程终止以及命令行参数和环境表

(一)main函数调用

main函数作为程序运行时的入口函数,它是如何被调用的呢?首先必须清楚一点,main函数也是一个函数,它只有被调用才能够执行。其实,在执行可执行程序时,在调用main函数之前,内核会先调用一个特殊的启动例程,将此启动例程作为可执行程序的起始地址。启动例程是如何作为可执行程序的起始地址的?这是由链接编译器设置的,而链接编译器则是由C编译器(如gcc编译器)调用的。启动例程作为可执行程序的起始地址主要做哪些工作呢?启动例程从内核取得命令行参数和环境变量值,以此来为main函数的调用做准备。

(二)命令行参数

当执行一个程序时,调用exec的进程可以将命令行参数传递给该程序。示例如下:

/*
 *File Name : argdemo.c
 *Author    : libing
 *Mail      : [email protected]
 *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); // setenv和unsetenv,若成功则返回0, 若出错则返回-1

说明如下:

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      : [email protected]
 *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("[email protected]");
	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.
[email protected]
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      : [email protected]
 *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

Linux环境编程之进程(一):main函数调用、进程终止以及命令行参数和环境表,布布扣,bubuko.com

时间: 2024-08-03 03:16:18

Linux环境编程之进程(一):main函数调用、进程终止以及命令行参数和环境表的相关文章

main函数——命令行参数与环境变量

main函数,是以C为基础开发平台的程序入口点,通常,我们写程序很少去关注函数main函数参数列表,而是简单给出下面这种情况. int main() {  system("pause");  return 0; } 打开MSDN,查看main函数, main( int argc, char *argv[ ], char *envp[ ] ){program-statements} 首先,我们先来看前两个参数,argc和 argv[ ],这两个主要是用来描述命令行参数的,但并不能说他们是

main 函数argc , argv 主命令行参数

ARGc和ARGv中的ARG指的是"参数"(ARGuments, argument counter 和 argument vector ) 至少有两个参数至主函数:ARGc和ARGv: 首先是一个至算提供的参数到程序, 第二个是对字符串数组的指针. 基本作用: argc, argv 用命令行编译程序时有用. 主函数main中变量(int argc, char *argv[ ])的含义 有些编译器允许将main()的返回类型声明为void,这已不再是合法的C++; main(int ar

linux平台学x86汇编(十五):使用命令行参数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在高级语言中,程序在命令行上启动时常常带一个或多个参数,在汇编语言中也可以实现这一特性.在实现这一特性之前,我们先了解一下linux如何从命令行执行程序. 每一个应用程序开始执行时,系统都会为该程序分配一块内存区域,并且每个程序都分配相同的虚拟内存地址.虚拟内存地址由操作系统映射到物理内存地址.在Linux中,程序的虚拟内存地址是从0x80480000开始,到地址0xbfff

UNIX环境编程学习笔记(17)——进程管理之进程的几个基本概念

lienhua342014-10-05 1 main 函数是如何被调用的? 在编译 C 程序时,C 编译器调用链接器在生成的目标可执行程序文件中,设置一个特殊的启动例程为程序的起始地址.当内核执行 C 程序时,在调用 main 前先调用这个特殊的启动例程,该启动例程从内核取得命令行参数和环境变量值. 2 共享库 共享库使得可执行文件中不再需要包含共用的库例程,而只需在所有进程都可引用的存储区中维护这种库例程的一个副本.程序第一次执行或者第一次调用某个库函数时,用动态链接方法将程序与共享库函数相链

第33课 main函数与命令行参数

1. main函数的概念 (1)C语言中main函数称之为主函数 (2)一个程序是从main函数开始执行的 [编程实验]main函数的原型究竟是什么 //以下四个main函数都是合法的 //第1种 //main() //{ //} //第2种 //void main() //{ //} //第3种:——标准的入口函数 int main() { return 0; } //第3种:——标准的入口函数 //int main() //{ // //没写返回值 //} [思考]为什么编译器支持那么多种不

聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]

聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数] 较之传统通过App.config和Web.config这两个XML文件承载的配置系统,.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命令行参数.环境变量和物理文件作为原始配置数据的来源,如果采用物理文件作为配置源,我们可以选择不同的格式(比如XML.JSON和INI等) .如果这些默认支持的配置源形式还不能满足你的需求,我们还可以通过注册自定义ConfigurationSour

.NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]

较之传统通过App.config和Web.config这两个XML文件承载的配置系统,.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命令行参数.环境变量和物理文件作为原始配置数据的来源,如果采用物理文件作为配置源,我们可以选择不同的格式(比如XML.JSON和INI等) .如果这些默认支持的配置源形式还不能满足你的需求,我们还可以通过注册自定义ConfigurationSource的方式将其他形式数据作为我们的配置来源. [ 本文已经同

UNIX环境编程学习笔记(20)——进程管理之exec 函数族

lienhua342014-10-07 在文档“进程控制三部曲”中,我们提到 fork 函数创建子进程之后,通常都会调用 exec 函数来执行一个新程序.调用 exec 函数之后,该进程就将执行的程序替换为新的程序,而新的程序则从 main 函数开始执行. UNIX 提供了 6 种不同的 exec 函数供我们使用.它们的原型如下所示, #include <unistd.h>int execl(const char *pathname, const char *arg0, ... /* (cha

UNIX环境编程学习笔记(22)——进程管理之system 函数执行命令行字符串

lienhua342014-10-15 ISO C 定义了 system 函数,用于在程序中执行一个命令字符串.其声明如下, #include <stdlib.h> int system(const char *cmdstring); system 函数在其实现中调用了 fork.exec 和 waitpid 函数.system 函数调用 fork 函数创建子进程,然后由子进程调用’/bin/sh -c cmdstring’ 来执行命令行参数 cmdstring,此命令执行完后便返回调用的进程