++++++APUE读书笔记-07进程环境(4)++++++
9、再谈环境变量
================================================
我们前面说了环境变量一般的形式是:"name=value",unix内核从来不会检查这些字符串,对于这些字符串的解释让程序自己来做。shell中就维护了大量的内部变量例如:HOME,USER,MAILPATH等等。
ISO C定义了一些可以获取环境变量值的函数,但是标准说值的内容是由实现定义的。
#include
char *getenv(const char *name);
返回和name相关的环境变量的值的指针,如果没有这个环境变量那么返回NULL。需要注意的是这个函数返回"name=value"字符串。我们一般调用getenv来获得特定的值,而不是直接访问environ。有些环境变量是特定的标准(例如XSI)才有的,而不是所有的标准才有这样的环境变量。
有时候我们想要修改一个环境变量或者添加一个环境变量,但是并不是所有的系统都支持这样的功能。下面的函数就和这个相关:
#include
int putenv(char *str);
int setenv(const char *name, const char *value,int rewrite);
int unsetenv(const char *name);
putenv函数以一个"name=value"字符串做为输入,把这个字符串放到环境列表中去。如果name已经存在了,那么旧的定义会被移除。
setenv函数设置name为value,如果name已经存在了,那么(a)如果重写的值非0,会先把已经定义的name给移除;(b)如果重写的值为0,那么已经存在的name定义不会被移除,name也不会被设置为新值也不会有任何错误发生。
unsetenv函数会把任何定义的name给移除。如果没有相应的定义也不会出现错误。
注意putenv和setenv的不同之处。setenv必须分配一块memory来创建name=value来根据参数创建字符串,putenv直接把传递给它的字符串自由地传递到environment.在linux和solaris中,putenv的实现会把我们传递给它的地址直接放到environment list中去。这时候,如果传递一个在stack上面的字符串将会出现错误。
修改环境变量列表的操作实际很复杂。前面已经说过,环境变量列表是指针数组,指针元素指向了实际的"name=value"字符串。环境变量字符串一般都存放在进程内存空间的顶部,在对阵的上面。如果删除一个字符串很简单,我们只需要找到该字符串在环境变量列表中相应的指针,然后把所有后面的指针向下移动一个单元就行了。但是如果添加一个字符串或者修改已经存在的字符串就很困难了。堆栈顶部的空间是不能被扩展的,因为它一直在进程地址空间的顶部,并且不能向上扩展;它也不能向下扩展,因为下面的stack不能被move。
如果我们修改一个已经存在的名字:
a)如果新value的size比原来的小或者等于原来的value,那么我们可以把新的字符串拷贝替换旧的字符串。
b)如果新value比旧大,我们必须为新的字符串分配空间,把新的字符串拷贝到相应的空间,然后把环境变量列表中相应的指针修改成指向新分配的空间。
如果我们想要增加一个环境变量,那么情况更为复杂.首先,我们的调用malloc为"name=value"分配空间,然后把字符串拷贝到这个空间。
a)然后,如果是我们第一次添加新的变量,我们需要调用malloc分配一个新的指针列表。我们把旧的环境变量指针列表内容拷贝到这个新的列表里面,然后把我们定义的新的环境变量的地址放到这个列表指针的最后。注意,如果原来的环境变量列表是在堆栈的顶部,我们需要把指针列表移动到heap中去。但是大多数在这个堆栈上面的列表的指针还是指向了name=value字符串。
b)如果我们不是第一次将新的环境变量添加到环境变量列表中去,那么我们需要知道我们已经在heap中为这个列表分配了空间,所以我们只需要调用realloc来分配可以容纳更多指针的空间。这个指向新定义环境变量的指针存放在列表的结尾,其后是null指针。
实际我们修改环境变量的时候,只能影响当前进程以及当前进程的子进程的环境变量。
原文中的参考资料中,给出了有关这些函数,以及相应的一些环境变量在系统上面的支持。这里不再给出,需要查看的读者可以从下面给出的参考网址中找到相应的内容。
参考:
阅读(394) | 评论(0) | 转发(0) |