[APUE]UNIX进程的环境(下)
一、共享库??共享库使得可执行文件中不再需要包含常用的库函数,而只需在所有进程都可存取的存储区中保存这种库例程的一个副本。程序第一次执行的时候或第一次调用某个库函数的时候,用动态链接方法将程序与共享库函数相链接,这减少了每个可执行文件的长度,但增加了一些运行时间开销。另一个优点就是可以用库函数的新版本来替换老版本而无需对该库的程序重新链接编译。 ?? ? 不同的系统使用不同的方法说明程序是否需要使用共享库。比较典型的有cc和ld命令的可选项。 二、 存储器分配??ANSI C说明了三个存储空间动态分配的函数
??这三个分配函数返回的指针一定是适当对齐的,使其可以用于任何数据对象。在一个特定的系统上,如果最苛刻的对齐要求是double,则对齐必须在8的倍数的地址单元处,那么这三个函数返回的指针都应这样对齐。 ??free函数释放的空间通常被送入可用存储区池,以后可在调用分配函数时再调用。 ??realloc如果在原存储区后有足够的空间可供扩充,则可在原存储区位置上向高地址方向扩充。并返回传给它的同样的指针值。如果在原存储区后没有足够的空间则realloc分配一个足够大的存储区,将现存的内容复制到新分配的存储区中。因为这种存储区会移动位置所以不应使任何指针指到该区。 ??realloc的最后一个参数是存储区的newsize而不是新旧长度之差。如果ptr是空指针,则realloc功能与malloc相同。用于分配一个制定长度newsize的存储区。 alloca函数?alloca函数是在当前函数的栈帧上分配存储空间。优点是:当函数返回时自动释放它所使用的栈帧,缺点是:某些系统在函数已经被调用后不能增加栈帧长度,于是也就不能支持alloca函数。 三、环境变量??ANSI C定义了一个函数getenv,可以用其取环境变量值,但是该标准又称环境的内容是由实现定义。
??POSIX.1和XPG3定义了某些环境变量。下表列出了由这两个标准定义并受到SVR4和4.3+BSD支持的环境变量。 ?? ? 除了取环境变量值,有时也需要设置环境变量,或者是改变现有变量的值,或者是增加新的环境变量。但是不是所有系统都支持这些操作。下表列出了不同的标准及实现支持的各种函数: ? ?? ? ? 中间三个函数的原型是:
??这三个函数的操作是:
四、setjpm和longjmp函数??在C中不允许使用跳跃函数的goto语句。而执行这种跳转功能的是非局部跳转函数setjmp和longjmp。非局部表示这不是子啊一个函数内的普通的C语言goto语句,而是在栈上跳过若干调用栈,返回到当前函数调用路径上的一个函数中。
??在希望返回到的位置调用setjmp,因为我们直接调用该函数所以其返回值为0。setjmp的参数env是一个特殊类型jmp_buf。这一数据类型是某种形式的数组,其中存放在调用longjmp时能用恢复栈状态的所有信息。一般,env变量是个全局变量,因为需要从另一个函数中引用它。 ? 下面是APUE上使用setjmp/longjmp的实例 ?? ? ? 执行main时,调用setjmp,它将所需的信息记入变量jmpbuffer中返回0。然后调用do_line,它又调用cm_add,假定在其中检测到一个错误。在cmd_add中调用longjmp之前,栈的形式如图所示 ? ??但是longjmp使栈回到执行main函数时的情况,也就是抛弃了cmd_add和do_line的栈帧。调用longjmp造成main中setjmp的返回。但是,这一次的返回值是1(longjmp的第二个参数)。 1. 自动、寄存器和易失变量??在main函数中,自动变量和寄存器变量的状态如何?当longjmp返回到main函数时,这些变量的值是否能恢复到以前调用setjmp时的值(即滚回原先值),或者这些变量的值保持为调用do_line时的值(do_line调用cmd_add,cmd_add又调用longjmp)?大多数实现并不滚回这些自动变量和寄存器变量的值,而所有标准则说它们的值是不确定的。如果有一个自动变量而又不想使其数值滚回可以定义其为具有volatile属性。说明为全局和静态变量的值在执行longjmp时保持不变。 ??我们通过以下程序来说明在调用longjmp后,自动变量、寄存器变量和易失变量的不同情况。 ?? #include <setjmp.h> static void f1(int,int); void f2(void); static jmp_buf jmpbuffer; int main() { count; register val; volatile sum; count 2; val = 3; sum = 4; if (setjmp(jmpbuffer) != 0) { printf("after longjmp: count = %d,val = %d,sum = %dn",count,val,sum); exit(); } count = 97; val = 98; sum = 99; f1(count,sum); } int i,1)">int j,1)"> k) { printf(in f1():count = %d,i,j,k); f2(); } ) { longjmp(jmpbuffer,1); } ? 如果以不带优化和带优化对此程序分别进行编译,然后运行它们得到的结果是不同的: ??易失变量不受优化的影响,在longjmp之后的值,是它在调用f1时的值。存放在存储器中的变量将具有longjmp时的值,而在CPU和浮点寄存器中的变量则恢复为调用setjmp时的值。不进行优化时所有这三个变量都存放在存储器中(会忽略val寄存器存储优化)。而进行优化时,count和val都存放在寄存器中。sum由于加了volatile限定符(该限定符修饰表示告诉编译器不要对这个变量进行优化)所以不会放到寄存器中。 2. 自动变量的潜在问题??对于如下程序,有一个open_data的函数,它打开了一个标准IO流,然后为该流设置缓存:
??该程序存在的问题是:当open_data返回时,它在栈上所使用的空间将由下一个被调用函数的栈帧使用。但是,标准IO函数仍然使用原先在栈上分配的存储空间作为流的缓存。这就产生了问题。为了改正这个问题应该在全局空间静态的(如static或extern),或者动态的为数组分配空间(malloc在堆上分配)。 五、getrlimit和settlimit函数??每个进程都有一组资源限制,其中一些可以用getrlimit和setrlimit函数查询和修改。
??对这两个函数的每一次调用都指定一个资源以及一下指向下列结构的指针。
? 在更改资源限制时,须遵循下列三条规则: ? (1) 任何一个进程都可将一个软限制更改为小于或等于其软限制。 ? (2) 任何一个进程都可降低其硬限制值,但它必须大于或等于其软限制值。这种降低,对普通用户是不可逆反的。 ? (3) 只有超级用户可以提高硬限制。 ? ? 一个无限量的限制通常由常数RLIM_INFINITY指定。 ? 这两个函数的resource参数取下列值之一。并非所有资源限制都受到SVR4和4.3+BSD的支持。
? 资源限制将影响到调用进程并由其子进程继承。这就意味着为了影响一个用户的所有后续进程,需将资源限制设置构造在shell中。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |