C语言标准库函数getenv可获取环境参数(根据参数名称),
函数声明:char* getenv(char*name);
其实现如下:
---------------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);
其实现如下:
---------------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;
的由来。