UNIX高级环境编程读书笔记(chapter7)

本文详细介绍了C语言程序的执行流程,包括从main函数开始执行,进程的正常终止和异常终止方式,以及内核如何使程序执行的唯一方法是调用exec函数。此外,文章还讲解了环境表的概念、存储器的典型安排、动态内存分配方法、环境变量的使用、setjmp和longjmp函数的作用以及getrlimit和setrlimit函数在资源限制查询与修改方面的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



7.1 main函数
C程序总是从main函数开始执行。


7.2 进程终止
有8种方式是进程终止
(1)从main返回
(2)调用exit()
(3)调用_exit或_Exit
(4)最后一个线程从启动例程返回
(5)最后一个线程调用pthread_exit


异常终止有三种方式:
(6)调用abort
(7)接到一个信号并终止
(8)最后一个线程对取消请求做出响应


7.2.1 exit()函数
有三个函数用于正常终止一个程序:_exit和_Exit立即进入内核,exit则先执行一些清理处理.
exit函数总是执行一个标准I/O库的清理关闭操作:为所有打开流调用fclose函数.
7.2.2 atexit()函数

atexit函数的参数是一个函数地址.exit函数调用这些函数的顺序与他们登记时候的顺序相反.


#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_exit2");
    }
    if (atexit(my_exit1) != 0)
    {
        err_sys("can't register my_exit2");
    }


    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");
}


执行结果:
main is done
first exit handler
first exit handler          


7.3 内核使程序执行的唯一方法是调用一个exec函数.进程自愿终止的唯一方法是显式的或隐式的调用_exit或_Exit.进程也
可非自愿的是一个信号使其终止.


7.5 环境表
每个程序都会接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的C字符串的地址。
全局变量environ则包含了该指针数组的地址: extern char **environ;
通常用getenv则和putenv函数来访问特定的环境变量,而不是用environ变量,但是,如果要查看整个环境,则必须使用environ指针。 


7.6 典型的存储器安排:


高地址   命令行参数和环境变量
 







未初始化的数据 (由exec初始化为0)


初始化的数据


(由exec从程序文件中读入)


正文




size(1)命令报告正文段, 数据段和bss段的总长度。

 
7.7 存储器分配
三个用于存储空间动态分配的函数:
(1)malloc 分配指定字节数的存储器.此存储区中的初始值不确定.
(2)calloc 为指定数量具指定长度的对象分配存储空间.该空间中的每一位都初始化为0
(3)realloc 更改以前分配区的长度.  注:realloc的最后一个参数是存储区的newsize,它不是新旧存储区长度只差.
函数free释放ptr指向的存储空间


7.8 环境变量
(1)putenv(): 取形式为 name = value的字符串,将其放到环境表中.如果name已经存在,则先删除其原来的定义.
(2)setenv():将name设置为value.
(3)unsetenv():删除name的定义.
7.9 setjmp 和 longjmp函数
在C中, goto语句是不能跨越函数的,而执行这类跳转功能的函数是setjmp和longjmp.这两个函数对于处理发生在深层嵌套函数调用中的出错情况是非常有用的.
#include "apue.h"
#include <setjmp.h>


#define TOK_ADD


jmp_buf jmpbuffer;


void do_line(char *);


void cmd_add(void);


int get_token(void);








int main(void)
{
    char line[MAXLINE];


    if (setjmp(jmpbuffer) != 0)
    {
        prtinf("error!\n");
    }


    while (fgets(line, MAXLINE, stdin) != NULL)
    {
        do_line(line);
    }
}


char *tok_ptr;


void do_line(char *ptr)
{
    int cmd;


    tok_ptr = ptr;


    while ((cmd = get_token()) > 0)
    {
        switch (cmd)
        {
            case TOK_ADD:
                    cmd_add();
                    break;
        }
    }
}




void cmd_add(void)
{
    int token;


    token = get_token();


    longjmp(jmpbuffer, 1);
}




int
get_token(void)
{


}



7.9 setjmp 和 longjmp函数实例
#include "apue.h"
#include <setjmp.h>


static void f1(int, int, int, int);
static void f2(void);


static jmp_buf jmpbuffer;
static int globval;
int main()
{
        int             autoval;
        register int    regival;
        volatile int    volaval;
        static int      statval;


        globval = 1;
        autoval = 2;
        regival = 3;
        volaval = 4;
        statval = 5;


        if (setjmp(jmpbuffer) != 0)
        {
            printf("After longjmp: \n");
            printf("globval = %d, autoval = %d, regival = %d, volaval = %d, statval = %d\n",
                    globval,    autoval,    regival,    volaval,    statval);


            exit(0);
        }


        globval = 95;
        autoval = 96;
        regival = 97;
        volaval = 98;
        statval = 99;


        f1(autoval, regival, volaval, statval);
        exit(0);


}


static void f1(i, j, k, l)
{
    printf("in f1():\n");
    printf("autoval = %d, regival = %d, volaval = %d, statval = %d\n",
                    i,  j,  k,  l);


    f2();
}


static void f2(void)
{
    longjmp(jmpbuffer, 2);
}




 
通过这一个实例,我们以理解到,如果要编写一个非全部跳转的可移植程序,则必须使用volatile属性。




7.10 getrlimit 和 setrlimit函数。
每个进程都有一组资源限制,其中一些可以用getrlimit 和 setrlimit函数查询和更改。
这两个函数的每一次调用都会指定一个资源,以及下列结构的直针:
struct rlimit
{
rlim_t rlim_cur;
rlim_t rlim_max;
}


在更改资源限制时,必需遵循下列三条规则:
(1)
(2)
(3)
常量 RLIM_INFINITY指定了一个无限量的限制.
#include "apue.h"


#if defined(BSD) || defined(MACOS)
#include <sys/time.h>
#define FMT "%1011d "
#else
#define FMT "%101d "
#endif


#include <sys/resource.h>


#define doit(name) pr_limits(#name, name)


static void pr_limits(char *, int);


int main(void)
{
    #ifdef RLIMIT_AS
        doit(RLIMIT_AS);
    #endif


    doit(RLIMIT_CORE);
    doit(RLIMIT_CPU);
    doit(RLIMIT_DATA);
    doit(RLIMIT_FSIZE);


    #ifdef RLIMIT_LOCKS
        doit(RLIMIT_LOCKS);
    #endif


    #ifdef RLIMIT_MEMLOCK
        doit(RLIMIT_MEMLOCK);
    #endif


    doit(RLIMIT_NOFILE);


    #ifdef RLIMIT_NPROC
        doit(RLIMIT_NPROC);
    #endif


    #ifdef RLIMIT_RSS
        doit(RLIMIT_RSS);
    #endif


    #ifdef RLIMIT_SBSIZE
        doit(RLIMIT_SBSIZE);
    #endif


    doit(RLIMIT_STACK);


    #ifdef RLIMIT_VMEM
        doit(RLIMIT_VMEM);
    #endif


    exit(0);
}


static void pr_limits(char *name, int resource)
{
    struct rlimit limit;
    if (getrlimit(resource, &limit) < 0)
    {
        err_sys("getrlimit error for %s", name);
    }


    printf("%-14s ", name);
    if (limit.rlim_cur == RLIM_INFINITY)
    {
        printf("(infinite) ");
    }
    else
    {
        printf(FMT, limit.rlim_cur);
    }


    if (limit.rlim_max == RLIM_INFINITY)
    {
        printf("infinite");
    }
    else
    {
        printf(FMT, limit.rlim_max);
    }


    putchar((int)'\n');
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值