C语言标准库函数getenv的实现

C语言标准库函数getenv可获取环境参数(根据参数名称),
函数声明:char* getenv(char*name);
extern char **environ

其实现如下:


---------------glibc-1.09.1/sysdeps/generic/getenv.c
[cpp]  view plain  copy
  1. /* Return the value of the environment variable NAME.  */  
  2. char *  
  3. DEFUN(getenv, (name), register CONST char *name)  
  4. {  
  5.   register CONST size_t len = strlen(name);  
  6.   register char **ep;  
  7.   
  8.   
  9.   if (__environ == NULL)  
  10.     return NULL;  
  11.   
  12.   
  13.   for (ep = __environ; *ep != NULL; ++ep)  
  14.     if (!strncmp(*ep, name, len) && (*ep)[len] == '=')  
  15.       return &(*ep)[len + 1];  
  16.   
  17.   
  18.   return NULL;  
  19. }  




其中全局指针__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(指向环境参数指针数组的指针)。


[cpp]  view plain  copy
  1. …………  
  2. #define __environ   environ  
  3. …………  
  4. static void start1();  
  5. …………  
  6. /* N.B.: It is important that this be the first function. 
  7.    This file is the first thing in the text section.  */  
  8. void  
  9. DEFUN_VOID(_start)  
  10. {  
  11.   start1();  
  12. }  
  13. …………  
  14. /* ARGSUSED */  
  15. static void  
  16. start1(ARG_DUMMIES argc, argp)  
  17.      DECL_DUMMIES  
  18.      int argc;  
  19.      char *argp;  
  20. {  
  21.   char **argv = &argp;  
  22.   
  23.   
  24.   /* The environment starts just after ARGV.  */  
  25.   __environ = &argv[argc + 1];  
  26.   
  27.   
  28.   /* If the first thing after ARGV is the arguments 
  29.      themselves, there is no environment.  */  
  30.   if ((char *) __environ == *argv)  
  31.     /* The environment is empty.  Make __environ 
  32.        point at ARGV[ARGC], which is NULL.  */  
  33.     --__environ;  
  34.   
  35.   
  36.   /* Do C library initializations.  */  
  37.   __libc_init (argc, argv, __environ);  
  38.   
  39.   
  40.   /* Call the user program.  */  
  41.   exit(main(argc, argv, __environ));  
  42. }  

正常的内存堆栈布局是这样的

地址从低到高:
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;

的由来。

你可能感兴趣的:(c++,内核)