- 论坛徽章:
- 0
|
一. 环境表(Environment List)
(这一节用英文原版的吧,主要是下面的图捣鼓了半天都画不出来)
Each program is also passed an environment list. Like the argument list, the environment list is an array of character pointers, with each pointer containing the address of a null-terminated C string. The address of the array of pointers is contained in the global variable environ:
extern char **environ;
For example, if the environment consisted of five strings, it could look like
Figure 7.5
. Here we explicitly show the null bytes at the end of each string. We'll call environ the environment pointer, the array of pointers the environment list, and the strings they point to the environment strings.
Figure 7.5. Environment consisting of five C character strings
[View full size image]
![]()
By convention, the environment consists of
name=value
strings, as shown in
Figure 7.5
. Most predefined names are entirely uppercase, but this is only a convention.
二、 C 程序的存储空间布局
C 程序一般有下面几部分组成:
正文段(text segment),初始化数据段(Initialized data segment),非初始化数据段(Uninitialized data segment, 通常称为 bss 段,block started by symbol),栈(Stack),堆(Heap)。
存储空间的典型布局:
Figure 7.6. Typical memory arrangement
![]()
三、获取和设置环境变量的函数
(这一节做的笔记在保存时出了问题,没有保存成功。后来就直接复制粘贴了原文,郁闷~)
ISO C defines a function that we can use to fetch values from the environment, but this standard says that the contents of the environment are implementation defined.
#include
char *getenv(const char *name);
Returns: pointer to value associated with name, NULL if not found
Note that this function returns a pointer to the value of a name=value string. We should always use getenv to fetch a specific value from the environment, instead of accessing environ directly.
Some environment variables are defined by POSIX.1 in the Single UNIX Specification, whereas others are defined only if the XSI extensions are supported.
Figure 7.7
lists the environment variables defined by the Single UNIX Specification and also notes which implementations support the variables. Any environment variable defined by POSIX.1 is marked with •; otherwise, it is an XSI extension. Many additional implementation-dependent environment variables are used in the four implementations described in this book. Note that ISO C doesn't define any environment variables.
Figure 7.7. Environment variables defined in the Single UNIX Specification
Variable
POSIX.1
FreeBSD 5.2.1
Linux 2.4.22
Mac OS X 10.3
Solaris 9
Description
COLUMNS
•
•
•
•
•
terminal width
DATEMSK
XSI
•
•
getdate(3) template file pathname
HOME
•
•
•
•
•
home directory
LANG
•
•
•
•
•
name of locale
LC_ALL
•
•
•
•
•
name of locale
LC_COLLATE
•
•
•
•
•
name of locale for collation
LC_CTYPE
•
•
•
•
•
name of locale for character classification
LC_MESSAGES
•
•
•
•
•
name of locale for messages
LC_MONETARY
•
•
•
•
•
name of locale for monetary editing
LC_NUMERIC
•
•
•
•
•
name of locale for numeric editing
LC_TIME
•
•
•
•
•
name of locale for date/time formatting
LINES
•
•
•
•
•
terminal height
LOGNAME
•
•
•
•
•
login name
MSGVERB
XSI
•
•
fmtmsg(3) message components to process
NLSPATH
XSI
•
•
•
•
sequence of templates for message catalogs
PATH
•
•
•
•
•
list of path prefixes to search for executable file
PWD
•
•
•
•
•
absolute pathname of current working directory
SHELL
•
•
•
•
•
name of user's preferred shell
TERM
•
•
•
•
•
terminal type
TMPDIR
•
•
•
•
•
pathname of directory for creating temporary files
TZ
•
•
•
•
•
time zone information
In addition to fetching the value of an environment variable, sometimes we may want to set an environment variable. We may want to change the value of an existing variable or add a new variable to the environment. (In the next chapter, we'll see that we can affect the environment of only the current process and any child processes that we invoke. We cannot affect the environment of the parent process, which is often a shell. Nevertheless, it is still useful to be able to modify the environment list.) Unfortunately, not all systems support this capability.
Figure 7.8
shows the functions that are supported by the various standards and implementations.
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 is not part of the Single UNIX Specification. It is used to remove all entries from the environment list.
The prototypes for the middle three functions listed in
Figure 7.8
are
[View full width]
#include
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
The operation of these three functions is as follows.
The putenv function takes a string of the form name=value and places it in the environment list. If name already exists, its old definition is first removed.
The setenv function sets name to value. If name already exists in the environment, then (a) if rewrite is nonzero, the existing definition for name is first removed; (b) if rewrite is 0, an existing definition for name is not removed, name is not set to the new value, and no error occurs.
The unsetenv function removes any definition of name. It is not an error if such a definition does not exist.
Note the difference between putenv and setenv. Whereas setenv must allocate memory to create the name=value string from its arguments, putenv is free to place the string passed to it directly into the environment. Indeed, on Linux and Solaris, the putenv implementation places the address of the string we pass to it directly into the environment list. In this case, it would be an error to pass it a string allocated on the stack, since the memory would be reused after we return from the current function.
It is interesting to examine how these functions must operate when modifying the environment list. Recall
Figure 7.6
: the environment listthe array of pointers to the actual name=value stringsand the environment strings are typically stored at the top of a process's memory space, above the stack. Deleting a string is simple; we simply find the pointer in the environment list and move all subsequent pointers down one. But adding a string or modifying an existing string is more difficult. The space at the top of the stack cannot be expanded, because it is often at the top of the address space of the process and so can't expand upward; it can't be expanded downward, because all the stack frames below it can't be moved.
If we're modifying an existing name:
If the size of the new value is less than or equal to the size of the existing value, we can just copy the new string over the old string.
If the size of the new value is larger than the old one, however, we must malloc to obtain room for the new string, copy the new string to this area, and then replace the old pointer in the environment list for name with the pointer to this allocated area.
If we're adding a new name, it's more complicated. First, we have to call malloc to allocate room for the name=value string and copy the string to this area.
Then, if it's the first time we've added a new name, we have to call malloc to obtain room for a new list of pointers. We copy the old environment list to this new area and store a pointer to the name=value string at the end of this list of pointers. We also store a null pointer at the end of this list, of course. Finally, we set environ to point to this new list of pointers. Note from
Figure 7.6
that if the original environment list was contained above the top of the stack, as is common, then we have moved this list of pointers to the heap. But most of the pointers in this list still point to name=value strings above the top of the stack.
If this isn't the first time we've added new strings to the environment list, then we know that we've already allocated room for the list on the heap, so we just call realloc to allocate room for one more pointer. The pointer to the new name=value string is stored at the end of the list (on top of the previous null pointer), followed by a null pointer.
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/105349/showart_2115928.html |
|