APUE读书笔记-第七章 进程环境

今天一天就结了一章,确实挺快的,不过第六章的内容现在还用不太到,但第七章的内容我认为就比较关键了,主要是有关于进程环境的内容

7.2 main函数

这一小节介绍了简单介绍了有关于main函数的内容,我认为讲的很简单,所以给大家分享一点我之前的学习体会:http://blog.csdn.net/u012927281/article/details/51356228

7.3 进程终止

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

  1. 从main返回。
  2. 调用exit。
  3. 调用_exit或_Exit。
  4. 最后一个线程从其启动例程返回。
  5. 从最后一个线程调用pthread_exit。

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

  1. 调用abort。
  2. 接到一个信号。
  3. 最后一个线程对取消请求做出响应。

以下三个函数用于正常终止一个程序:_exit或_Exit立即进入内核,exit则先执行一些清理处理,然后返回内核。

函数原型如下:

#include <stdlib.h>
extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
extern void _Exit (int __status) __THROW __attribute__ ((__noreturn__));
#include <unistd.h>
extern void _exit (int __status) __attribute__ ((__noreturn__));

 通过这三个函数所使用的头文件不同可以看出,_exit是系统调用,而另外两个函数是库函数。

以下内容直接引用自APUE:

“由于历史原因,exit函数总是执行一个标准I/O库的清理关闭工作:对于所有打开流调用fclose函数,这就造成输出缓冲中的所有数据都被冲洗(写入文件或输出)。”

若main的返回类型是整型,并且main执行到最后一条语句时返回(隐式返回),那么该进程的终止状态是0。其他情况下,进程的终止状态是未定义的。这一点可以通过stddef.h中相关的定义验证。

#define	EXIT_FAILURE	1	/* Failing exit status.  */
#define	EXIT_SUCCESS	0	/* Successful exit status.  */

程序运行结束后,这个状态可以通过"$?"进行查询。

终止处理程序注册函数:

#include <stdlib.h>
extern int atexit (void (*__func) (void)) __THROW __nonnull ((1));
根据ISO C的规定,一个进程可以登记多至32个函数,这些函数由exit自动调用,通过atexit函数来注册这些函数。exit调用这些函数的顺序与他们登记时候的顺序相反。

根据ISO C和POSIX.1,exit首先调用各终止处理程序,然后关闭(通过fclose)所有打开流。POSIX.1扩展了ISO C标准,如若程序调用exec函数族中的任一函数,则将清除所有已安装的终止处理程序。

这里还要注意的一点是内核使程序执行的唯一方法是调用一个exec函数。进程自愿终止的唯一方法是显示或隐式地(通过调用exit)调用_exit或_Exit。进程也可非自愿地由一个信号使其终止。

一个C程序是如何启动和终止的见下图。


7.4 命令行参数的有关内容就不给大家详细分享了。

7.5 环境表

每个程序都接收到一张环境表。使用全局变量environ对这一环境表进行引用,environ为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串。

7.6 C程序的存储空间布局

这一章也不详细分析了,有关于这部分的内容请见我有关于《程序员的自我修养》的读书笔记。

7.7 共享库

这一章也不详细分析了,这部分内容还是请见我有关于《程序员的自我修养》的读书笔记。

7.8 存储空间分配

这一部分也先不说了,不过有机会的话要把malloc的源码简单分析一下。

7.9 环境变量

ISO C定义了一系列函数用于查询、修改环境变量,首先来看查询环境变量的函数。

#include <stdlib.h>
extern char *getenv (const char *__name) __THROW __nonnull ((1)) __wur;

该函数返回name对应的value值。

再来看看更改环境变量的函数:

#include <stdlib.h>
extern int putenv (char *__string) __THROW __nonnull ((1));
extern int setenv (const char *__name, const char *__value, int __replace)
     __THROW __nonnull ((2));
extern int unsetenv (const char *__name) __THROW __nonnull ((1));

putenv取形式如name=value的字符串,将其放到环境表中。如果name已经存在,则先删除原来的定义。

setenv将name设置为value。如果在环境中name已经存在,那么(a)若rewrite非0,则首先删除其现有的定义;(b)若rewrite为0,则不删除其现有定义(name不设置为新的value,而且也不出错)。

unsetenv删除name的定义,即使不存在这种定义也不算出错。

putenv与setenv的区别在于setenv必须分配存储空间,以便依据其参数创建name=value字符串。但putenv存在一定的隐患,若将存放在栈中的字符串作为参数传递给putenv函数,但从当前函数返回时,其栈帧占用的存储区可能将被重用。

关于7.10节与7.11节的内容也不给大家分享了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值