环境变量

环境变量

环境变量通常是这样的形式:

name=value

UNIX内核不理会它的名字,只把它解释给多种应用程序。

ISO C定义了得到环境变量值的函数,但是环境变量的值是由实际环境值定义的。

#include <stdlib.h>

char *getenv(const char *name);

Returns: pointer to value associated with name, NULL if not found

注意这个函数返回一个指向name=value中value的指针。应该一直使用getenv获得得定的环量变量,而不是直接使用environ

一些环境变量被POSIX.1定义在Single UNIX Specification中,另一些定义在XSI扩展中。注意:ISO C没定义任何环境变量。

另外添加、删除、修改环境变量并不是所有系统都支持:

Figure 7.8. Support for various environment list functions

Function

ISO C

POSIX.1

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

getenv

putenv

XSI

setenv

unsetenv

clearenv

clearenv 并不是single UNIX Specification中的一部分。它常被用于从环境变量列表中删除所有内容。

下面是三个函数的原型:

  #include <stdlib.h>

  int putenv(char *str);

  int setenv(const char *name, const char *value,  int rewrite);

  int unsetenv(const char *name);

All return: 0 if OK, nonzero on error

这三个函数的操作如下:

  • putenv函数的参数是一个name=value的字符串,并把它放到环境变量的列表里。如果name已经存在,先删除之前的定义。
  • setenv函数为value设置一个name。如果name已经存在环境变量列表中:(a)如果rewrite非零,已经存在的name会被删除。(b)如果rewrite是零,民经存在的name保持不变,新值也不会被设置,而且不会提示错误。
  • unsetenv函数移除任何定义过的name。如果name没定义过,也不会有任何错误提示。

注意setenvputenv之间的不同。因为setenv从它的参数中建立name=value字符串,必须为该字符串分配内存。而putenv是直接把字符串传给环境变量。在linux和Solaris上,putenv直接将参数的字符串地址传给环境变量列表。在本例中,传递在栈上分配的字符串到环境变量,很有可能发生错误,因为在函数返回后,栈的地址可能被重新使用。

这里介绍当修改环境变量列表时,这些函数如何操作。回忆图7.6:

figure7.6

环境变量列表的指针数组(每个指针指向实际的name=value字符串)和环境变量字符串典型存储在进程内存空间的顶部,栈的上面。删除字符串很简单,只要在环境变量列表中找到这个指针,并移动所有子序列指针向下移动一个位置。反之添加或修改一个字符串要更困难。栈顶的空间不能扩展,因为它通常是在进程的地址空间顶部。同样也不能向下扩展,因为所有在下面的栈帧不能移动。

1.如果修改一个存在的name

a. 如果新value的尺寸小于或等于已经存在的值,可以仅复制新字符串覆盖旧的。

b.如果新value的尺寸大于旧的,那就必须为新值malloc一个空间,复制新值到这个空间,之后在环境变量列表中替换旧的指针。

2.如果要添加一个新name,这会更复杂。首先,必须为name=value字符串分配一个新的空间,然后复制字符串到这个区域。

a.然后,如果这是第一次添加新name,必须调用malloc获得一个新的空间,把之前环境变量列表复制到这个新空间,然后在这个指针数组的结尾存储一个指向name=value字符串的指针。最后,使用environ指向这个新的指针数组。注意,如图7.6所示,如果原始的环境变量列表已经包含在栈顶之上。那么必须移动这个指针列表到堆,但这个列表中的多数指针依然指向栈顶之上的字符串。

b.如果这不是第一次添加新name,那也就是说之前已经在堆上分配了空间,所以只要调用recalloc去扩展空间的大小就可以了。指向新的name=value字符串的指针,被存储在列表的结尾(在之前空指针的上面),它的后面再跟一个空指针。

发表评论