APUE: Process Environment

感情迁移 提交于 2019-12-05 19:39:36

main函数和进程终止

    当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址。启动例程从内核取得命令行参数和环境变量值,然后调用main函数。

存在8种方式终止进程:

5种正常终止:

1. 从main返回

2. 调用exit

3. 调用_exit或者_Exit

4. 最后一个线程从启动例程中返回.

5. 最后一个线程调用pthread_exit.

3种异常终止:

1. 调用abort

2. 接收信号并终止.

3. 最后一个线程对取消请求做出响应.

Exit函数

#include <stdlib.h>

void exit(int status);

void _Exit(int status);

#include <unistd.h>

void _exit(int status);

_exit和_Exit会立马返回到内核, 而exit则会清除线程后返回内核.

在main函数中, 如果没有显式return/exit, 则默认返回0:

#include <stdio.h>

int main(void)
{
    printf("hello world\n");
}

终端输出:

leicj@leicj:~/test$ ./a.out
hello world
leicj@leicj:~/test$ echo $?
0

atexit函数

    一个进程可以登记多达32个函数,这些函数将由exit自动调用。我们称这些函数为终止处理程序,并调用atexit函数来登记这些函数。

终止处理程序:

#include <stdio.h>

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

int main(void)
{
    if (atexit( my_exit2 ) != 0)
        printf("can't register my_exit2\n");
    if (atexit( my_exit1 ) != 0)
        printf("can't register my_exit1\n");
    if (atexit( my_exit1 ) != 0)
        printf("can't register my_exit1\n");
    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");
}

程序输出:

leicj@leicj:~/test$ ./a.out
main is done
first exit handler
first exit handler
second exit handler

 

C程序的存储空间布局

1. 正文段:由CPU执行的机器指令部分

2. 初始化数据段:包含了程序中需明确的赋初值的变量

3. 非初始化数据段: 声明在函数之外的变量存放的地方, 通常会被内核初始化为0或者null.

4. 栈:自动变量以及每次函数调用时所需保存的信息都存放在此段中

5. 堆:进行动态分配

leicj@leicj:~/test$ size /usr/bin/cc /bin/sh
   text    data     bss     dec     hex filename
 902577    8048    9696  920321   e0b01 /usr/bin/cc
 143301    4792   11312  159405   26ead /bin/sh

内存分配

ISO C定义三个函数用于分配内存, 一个函数用于释放内存.

#include <stdlib.h>

void *malloc(size_t size);

void *calloc(size_t nobj, size_t size);

void *realloc(void *ptr, size_t newsize);

            returns: 成功返回非空指针, 失败返回NULL

void free(void *ptr);

malloc: 分配特定字节的内存, 初始值不确定.

calloc: 分配特定数量的对象, 每个对象的大小为size.

realloc: 用于增加或减少内存.

关于环境变量

#include <stdio.h>
#include <stdlib.h>

extern char *environ;
int main( void )
{
    putenv("hello=world");
    setenv("hello1", "world1", 0);

    printf("%s\n", getenv("hello"));
    printf("%s\n", getenv("hello1"));

    unsetenv("hello");
    unsetenv("hello1");

    return 0;
}

程序输出:

leicj@leicj:~/test$ ./a.out
world
world1

 

setjmp和longjmp

#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuffer;
void fun1();
void fun2();
int main( void )
{
    int     bFun1 = 0;
    int     bFun2 = 0;
    bFun1 = setjmp(jmpbuffer);
    bFun2 = setjmp(jmpbuffer);
    printf("the return value is:%d---%d\n", bFun1, bFun2);
    printf("main done\n");
    if ( bFun1 || bFun2 ) {
        exit( 0 );
    }
    fun1();
    fun2();

    return 0;
}

void fun1()
{
    printf("fun1\n");
    longjmp( jmpbuffer, 1 );
}

void fun2()
{
    printf("fun2\n");
    longjmp( jmpbuffer, 2 );
}

程序输出:

leicj@leicj:~/test$ ./a.out
the return value is:0---0
main done
fun1
the return value is:0---1
main done

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!