进程环境之main函数、进程终止、命令行参数以及环境表

main函数

C程序总是从main函数开始执行。main函数原型是:

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

argc是命令行参数个数,argv是指向参数的各个指针所构成的数组。

当内核执行C程序时,在调用main函数前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址——这是有连接编辑器设置的,而连接编辑器则由C编辑器调用。启动例程从内核取得命令行参数和环境变量值,然后按上述方式调用main函数做好安排。

进程终止

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

  • main返回
  • 调用exit
  • 调用_exit_Exit
  • 最后一个线程从其启动例程返回
  • 从最后一个线程调用pthread_exit

异常终止有3种方式,它们是:

  • 调用abort函数
  • 接到一个信号
  • 最后一个线程对取消请求做出响应

1. 退出函数

3个用于正常终止的函数。_exit_Exit函数立即进入内核,exit函数先执行一些清理处理,然后返回内核。

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

main函数返回一个整型值与该值调用exit是等价的。于是在main函数中exit(0);等价于return (0);

测试示例:

#include <stdio.h>
main()
{
    printf("hello, world\n");
}

2. 函数atexit

按照ISO C的规定,一个进程可以登记多至32个函数,这些函数将由exit函数自动调用。这些函数被称之为终止处理程序,并调用atexit函数来登记这些函数。

#include <stdlib.h>
int atexit(void (*func)(void));
返回值:若成功,返回 0;若出错,返回非 0

atexit函数的参数是一个函数地址,当调用此函数时无需向它传递任何参数,也不期望它返回一个值。exit函数调用这些函数时的顺序与它们被登记时的顺序相反。同一函数如果被登记多次,也会被调用多次。
测试示例:

#include "../../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");
}

结果如下:

由上图可知,终止处理函数的执行顺序与它们的注册顺序是相反的,并且my_exit1函数两次被注册,则其就被执行两次。

命令行参数

当执行一个程序时,调用exec的进程可将命令行参数传递给该新程序。这是UNIX shell的一部分常规操作。
测试示例:
将所有命令行参数回显到标准输出上,但是,通常的echo程序无法回显第0个参数。

#include "../../include/apue.h"

int main(int argc, char *argv[])
{
    int i;
    //for(i = 0; i < argc; i++)
    for(i = 0; argv[i] != NULL; i++)    
        printf("argv[%d]: %s\n", i, argv[i]);
    return 0;
}

结果如下:

环境表

每个程序都接收到一张环境表,与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以null(’\0’)结束的C字符串的地址。全局变量environ则包含了该指针数组的地址:

extern char **environ;

我们称environ为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串。在历史上,大多数UNIX系统支持main函数带3个参数,其中第3参数就是环境表地址:

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

因为ISO C规定main函数只有两个参数,而且第3个参数与全局变量environ相比并未带来更多益处,所以POSIX.1也规定应使用environ而不是第3个参数。通常使用getenvputenv函数来访问环境变量,而不是用environ变量。但是,如果要查看整个环境,则必须使用environ指针。

发布了229 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40073459/article/details/104419018