C语言标准库函数getenv可获取环境参数(根据参数名称),
函数声明:char* getenv(char*name);
extern char **environ
其实现如下:
---------------glibc-1.09.1/sysdeps/generic/getenv.c
其中全局指针__environ指向环境参数串的指针数组,通过循环匹配找到指定的参数名称,获取=后的参数值并返回其指针。
那么__environ是在哪定义的呢?是在start.c中。
---------------glibc-1.09.1/sysdeps/unix/start.c
C程序链接时,这部分stub代码会链接到在程序开始处,_start是C程序真正的入口,_start调用start1,
而start1在调用初始化代码__libc_init后会调用main()。
从下面的代码看出,为什么main中末尾无需exit(),因为start1代劳了。至于堆栈中的argc,argv,envp
这些都是操作系统在调用系统调用execve执行程序时就安排好的,start1的形参可以去到这些进程参数和环境变量,
全局指针environ则等于envp(指向环境参数指针数组的指针)。
正常的内存堆栈布局是这样的
int argc
char** argv(指针数组,0结尾)
char** envp(指针数组,0结尾)
string[] arg(顺序排列的参数串数组,每个参数串0结尾)
string[] env(顺序排列的环境参数串数组,每个参数串0结尾)
其中argv[0]指向arg[0],argv[1]指向arg[1],……。
正常情况 &argv[argc+1]=envp,但是如果环境参数没有,那么堆栈中就没有envp指针数组和env串数组,那么argv后就直接是
arg的参数串数组了,此时堆栈布局如下:
int argc
char** argv(指针数组,0结尾)
string[] arg(顺序排列的参数串数组,每个参数串0结尾)
所以有&argv[argc+1]=*argv (第一个参数指针argv[0]是指向第一个参数串的),这是上述代码中
if ((char *) __environ == *argv)
/* The environment is empty. Make __environ
point at ARGV[ARGC], which is NULL. */
--__environ;
的由来。
函数声明:char* getenv(char*name);
extern char **environ
其实现如下:
---------------glibc-1.09.1/sysdeps/generic/getenv.c
- /* Return the value of the environment variable NAME. */
- char *
- DEFUN(getenv, (name), register CONST char *name)
- {
- register CONST size_t len = strlen(name);
- register char **ep;
- if (__environ == NULL)
- return NULL;
- for (ep = __environ; *ep != NULL; ++ep)
- if (!strncmp(*ep, name, len) && (*ep)[len] == '=')
- return &(*ep)[len + 1];
- return NULL;
- }
其中全局指针__environ指向环境参数串的指针数组,通过循环匹配找到指定的参数名称,获取=后的参数值并返回其指针。
那么__environ是在哪定义的呢?是在start.c中。
---------------glibc-1.09.1/sysdeps/unix/start.c
C程序链接时,这部分stub代码会链接到在程序开始处,_start是C程序真正的入口,_start调用start1,
而start1在调用初始化代码__libc_init后会调用main()。
从下面的代码看出,为什么main中末尾无需exit(),因为start1代劳了。至于堆栈中的argc,argv,envp
这些都是操作系统在调用系统调用execve执行程序时就安排好的,start1的形参可以去到这些进程参数和环境变量,
全局指针environ则等于envp(指向环境参数指针数组的指针)。
- …………
- #define __environ environ
- …………
- static void start1();
- …………
- /* N.B.: It is important that this be the first function.
- This file is the first thing in the text section. */
- void
- DEFUN_VOID(_start)
- {
- start1();
- }
- …………
- /* ARGSUSED */
- static void
- start1(ARG_DUMMIES argc, argp)
- DECL_DUMMIES
- int argc;
- char *argp;
- {
- char **argv = &argp;
- /* The environment starts just after ARGV. */
- __environ = &argv[argc + 1];
- /* If the first thing after ARGV is the arguments
- themselves, there is no environment. */
- if ((char *) __environ == *argv)
- /* The environment is empty. Make __environ
- point at ARGV[ARGC], which is NULL. */
- --__environ;
- /* Do C library initializations. */
- __libc_init (argc, argv, __environ);
- /* Call the user program. */
- exit(main(argc, argv, __environ));
- }
正常的内存堆栈布局是这样的
地址从低到高:
int argc
char** argv(指针数组,0结尾)
char** envp(指针数组,0结尾)
string[] arg(顺序排列的参数串数组,每个参数串0结尾)
string[] env(顺序排列的环境参数串数组,每个参数串0结尾)
其中argv[0]指向arg[0],argv[1]指向arg[1],……。
正常情况 &argv[argc+1]=envp,但是如果环境参数没有,那么堆栈中就没有envp指针数组和env串数组,那么argv后就直接是
arg的参数串数组了,此时堆栈布局如下:
int argc
char** argv(指针数组,0结尾)
string[] arg(顺序排列的参数串数组,每个参数串0结尾)
所以有&argv[argc+1]=*argv (第一个参数指针argv[0]是指向第一个参数串的),这是上述代码中
if ((char *) __environ == *argv)
/* The environment is empty. Make __environ
point at ARGV[ARGC], which is NULL. */
--__environ;
的由来。