七.进程环境
atexit函数:
函数atexit登记终止处理程序(函数),一个进程最多可以登记32个终止处理函数,这些函数由exit自动调用(return 语句也可以调用),即在程序结束时调用。
#include<stdlib.h>
int atexit(void (*func) (void));
环境表:
每个程序都会接受到一张环境表。环境表是一个字符指针数组。
全局变量environ包含了该指针数组的地址:
extern char **environ
例如:
环境包含5个字符串,每个字符串结尾处都显式地有一个null字节。environ是环境指针,指针数组为环境表。各指针指向的字符串为环境字符串。
C程序的存储空间布局:
C程序由下列几部分组成:
-正文段。这是由CPU执行的机器指令部分。
-初始化数据段。通常称为数据段。包含了程序中需明确地赋初值的变量。如:int maxcount = 99;
-未初始化数据段。通常称为bss段。如:long sum[1000];
-栈。自动变量以及每次函数调用时所需保存的信息都存放在此段中。
-堆。通常在堆中进行动态存储分配。
size命令可以报告正文段、数据段、和bss段的长度。dec和hex分别表示十进制和十六进制表示的三段总长度
存储空间分布
三个用于存储空间动态分配的函数:
这三个分配函数所返回的指针一定是适当对齐的,使其可用于任何数据对象。
大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度、指向下一个分配块的指针等。
如果超过一个已分配区的尾端或者在已分配区起始位置之前进行写操作,则会改写另一块的管理记录信息。这样的错误是灾难性的。
其它错误:
-释放一个已释放的块
-若对一个进程调用malloc函数,却忘记调用free函数,那么该进程占用的存储空间就会连续增加,这称为泄漏(C++中new,不delete)
环境变量
函数getenv,可以用其取环境变量值。此函数返回一个指针指向name = value字符串中的value.
———————————————————————————————————————————————————————————
这些函数在修改环境表时是如何进行操作的呢?
答:环境表(指向实际name=value字符串的指针数组)和环境字符串通常存放在进程存储空间的顶部(栈)。
删除一个字符串很简单:先在环境表中找到该指针,然后将所有后续指针都向环境表首部顺次移动一个位置。
———————————————————————————————————————————————————————————
函数setjmp和longjmp
函数setjmp和longjmp执行类型跳转功能
在希望返回到的位置调用setjmp , setjmp参数env的类型是一个特殊类型jmp_buf , 其中存放在调用longjmp时能用来恢复栈状态的所有信息。因为需要在longjmp函数中引用env变量,所以通常将env变量定义为全局变量。
当检查到一个错误时,用两个参数调用longjmp,第一个是setjmp所用的env,第二个参数是个非0的val值,它将成为setjmp函数返回的值。根据返回的值可以判断是从哪个longjmp跳转的,从而判断出程序出错在哪。
#include "apue.h"
#include<setjmp.h>
#define TOK_ADD 5
jmpbuf jmpbuffer; //声明为全局变量
int main(void)
{
char line[MAXLINE];
if(setjmp(jmpbuffer) != 0)
print("error");
while (fgets(line,MAXLINE,stdin) != NULL)
do_line(line);
exit(0);
}
...
void cmd_add(void)
{
int token;
token = get_token();
if (token < 0) //发生错误
longjmp(jmpbuffer,1); //设置返回值为1,根据返回值判断发生错误的地方。
}
1.自动变量、寄存器变量和易失变量
问题:在main函数中,自动变量和寄存器变量的状态如何?当longjmp返回到main函数时,这些变量的值能否回复到以前调用setjmp时的值(即回滚原先值)?
答案是:看情况。大多数情况下值是不确定的。如果有个自动变量,而又不想使其回滚,可定义其具有volatile属性。声明为全局变量和静态变量的值在执行longjmp时保持不变。
实例:通过程序说明在调用longjmp后,自动变量,全局变量,寄存器变量,静态变量,易失变量的不同情况。
#include<stdio.h>
#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(void)
{
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) { //直接调用setjmp返回0
printf("after longjmp:\n");
printf("globval = %d, autoval = %d, regival = %d, volaval = %d, statval = %d\n",globval,autoval,regival,volaval,statval);
exit(0);
}
/*
* 在setjmp之后,在longjmp之前。改变各变量的值
*/
globval = 95; autoval = 96; regival = 97; volaval = 98; statval = 99;
f1(autoval,regival,volaval,statval); //不返回
exit(0);
}
static void f1(int i, int j, int k, int l)
{
printf("in f1():\n");
printf("globval = %d, autoval = %d, regival = %d, volaval = %d, statval = %d\n",globval,i,j,k,l);
f2();
}
static void f2(void)
{
longjmp(jmpbuffer,1);
}
gcc testjmp.c //不进行优化的编译
gcc -O testjmp.c //进行优化的编译
全局变量,静态变量,易失变量不受优化的影响,在longjmp之后,它们的值是最近所呈现的值。不能回滚。
函数getrlimit和setrlimit
对这两个函数的每一次调用都指定一个资源以及一个指向下列结构的指针。