工学1号馆

home

Unix进程环境

By Wu Yudong on October 24, 2016

1、main函数

main函数声明:

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

参数说明:

  • argc:命令行参数个数
  • argv:指向参数列表数组的指针

main函数启动前:

  • C程序由内核执行,通过系统调用exec;
  • main函数调用前,执行指定的启动路径(start-up routine);
  • 可执行文件认为此地址为程序的启动地址,该地址由链接器指定;
  • 启动路径从内核获取参数列表和环境变量,使得main函数可以在稍后被调用时可以获取这些变量。

本文地址:http://wuyudong.com/2016/10/24/2884.html,转载请注明出处。

2、进程终止

有8种方式使进程终止,其中5中为正常终止,它们是

1) 从main返回

2) 调用exit

3) 调用_exit或_Exit

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

5) 最后一个线程调用pthread_exit

异常终止有3中方式

6) 调用abort

7) 接到一个信号并终止

8) 最后一个线程对取消请求做出相应

(1)退出函数

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

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

_exit和_Exit立刻返回到内核;

exit函数返回内核前会进行一些清理环境工作;

返回一个整数和调用exit函数,并传入该整数的作用是相同的:exit(0);  与 return 0;

(2)atexit函数

#include <stdlib.h>
int atexit(void (*func) (void));

函数细节

  • 每个进程可以注册32个函数,这些函数可以在主函数调用exit时自动被调用
  • 通过atexit注册的退出时处理函数称为退出句柄(exit handlers)
  • 这些退出句柄的调用顺序为注册时的相反顺序
  • exit函数第一次调用退出句柄时,会关闭所有打开的流
  • 如果主程序调用了exec系列函数,则所有注册的退出句柄都会被清空

下面写个程序说明如何使用atextit函数

#include "apue.h"

static void    my_exit1(void);
static void    my_exit2(void);

int
main(void)
{
    if (atexit(my_exit2) != 0)
        err_sys("can't register my_exit2");

    if (atexit(my_exit1) != 0)
        err_sys("can't register my_exit1");
    if (atexit(my_exit1) != 0)
        err_sys("can't register my_exit1");

    printf("main is done\n");
    return(0);
}

static void
my_exit1(void)
{
    printf("first exit handler\n");
}

static void
my_exit2(void)
{
    printf("second exit handler\n");
}

运行程序:

wu@ubuntu:~/apue.3e/environ$ gcc doatexit.c -o doatexit -lapue
wu@ubuntu:~/apue.3e/environ$ ./doatexit
main is done
first exit handler
first exit handler
second exit handler

3、命令行参数

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

写一个程序用来打印所有的命令行参数

#include "apue.h"

int
main(int argc, char *argv[])
{
    int i;

    for (i = 0; i < argc; i++)    
        printf("argv[%d]: %s\n", i, argv[i]);
    exit(0);
}

运行程序

wu@ubuntu:~/apue.3e/environ$ ./echoarg wu yu dong
argv[0]: ./echoarg
argv[1]: wu
argv[2]: yu
argv[3]: dong


环境表

在每个进程启动时,都会接到一张环境表。环境表是一个字符指针数组,其中每个指针包含一个以 null 结束的 C 字符串的地址。全局变量environ 则包含了该指针数组的地址,

extern char **environ;

写个程序打印程序所有的环境变量值

#include<stdio.h>
extern char **environ;
int main()
{
    char **p;
    p = environ;
    while(*p) {
        printf("%s\n", *p);
        p++;
    }
    return 0;
}

运行程序

XDG_VTNR=7
XDG_SESSION_ID=c2
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/wu
SELINUX_INIT=YES
CLUTTER_IM_MODULE=xim
SESSION=ubuntu
GPG_AGENT_INFO=/run/user/1000/keyring-cVSjMP/gpg:0:1
TERM=xterm
VTE_VERSION=3409
XDG_MENU_PREFIX=gnome-
SHELL=/bin/bash
WINDOWID=58812881
OLDPWD=/home/wu/apue.3e
UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1965
GNOME_KEYRING_CONTROL=/run/user/1000/keyring-cVSjMP
GTK_MODULES=overlay-scrollbar:unity-gtk-module
ANT_HOME=/home/wu/opt/apache-ant-1.8.3
USER=wu
……………………

可以看到有很多的name与value

环境变量

环境字符串的形式通常为,name=value。

ISO C 定义了一个函数 getenv,用于获取环境变量值。

#include <stdlib.h>
char *getenv(const char *name);

返回值:指向与name关联的value的指针,若为找到则返回NULL

POSIX.1 定义了两个函数 putenv 和 setenv,用于设置环境变量,

#include <stdlib.h>
int putenv(char *str);

返回值:若成功则返回0,若出错则返回非0值

putenv 的参数是形式为 name=value 的字符串的指针,将参数放到环境表中。如果 name 已经存在,则先删除其原有的定义。

#include <stdlib.h>
int setenv(const char *name, const char *value, int rewrite);

返回值:若成功则返回0,若出错则返回-1

setenv 函数将环境变量 name 的值设置为 value。如果环境表中 name 已存在,那么

• 若 rewrite 为非 0 值,则首先删除其现有定义。

• 若 rewrite 为 0,则不删除其现有定义,name 不设置为新的 value,也不出错。

写个程序

#include<stdio.h>
#include<stdlib.h>
int main()
{
    printf("%s\n", getenv("LOGNAME"));
    printf("%s\n", getenv("HOME"));
    return 0;
}

运行结果

wu@ubuntu:~/apue.3e/environ$ vim getenv.c
wu@ubuntu:~/apue.3e/environ$ gcc getenv.c -o getenv
wu@ubuntu:~/apue.3e/environ$ ./getenv
wu
/home/wu

如果文章对您有帮助,欢迎点击下方按钮打赏作者

Comments

No comments yet.
To verify that you are human, please fill in "七"(required)