zoukankan      html  css  js  c++  java
  • 环境变量 environment varible

    wiki上有简单的说到, environment varibles are a set of dynamic named values that can affect the way running processes will behave on a computer。  也就是说环境变量为进程的运行提供了一个环境,比如shell这个进程就会使用PATH这个环境变量来搜寻可执行文件。不同的进程可以以不同的方式来使用或是说来解释同一个环境变量, 这是显而易见的,因为环境变量就是存在于进程空间的一组字符串。

    1 关于环境变量的一个测试程序

    在unix中,每个进程都有属于自己的一组环境变量,这些环境变量,或是这个全局字符串,是子进程从父进程继承过来的,如果子进程不对环境变量做修改的话,当然是和父进程的一模一样,下面用一个测试程序来检测一下

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 extern char ** environ;
     5 void show_env();
     6 int main(int argc, char *argv[]){ 
    8
    if(fork() > 0){ //fork出子进程 9 // show_env(); 10 char *path_value = malloc(200); 11 path_value = getenv("PATH"); 12 printf("int parent : PATH=%s\n", path_value); 13 }else{
    //修改环境变量PATH, 并且加上一个环境变量字串 "wangyu=wangyu"
    14 setenv("PATH", "wy", 1); 15 putenv("wangyu=wangyu"); 16 char *path_value = malloc(200); 17 path_value = getenv("PATH"); 18 printf("int child : PATH=%s\n", path_value); 19 // show_env(); 20 }
    //打印出环境变量表的地址
    21 printf("environment table address :%p\n", environ); 22 return 0; 23 }
    // 打印出一个进程的所有环境变量及相关地址
    24 void show_env(){ 25 char ** env = environ; 26 int i = 0; 27 while(*env){ 28 printf("index : %d\nenv address : %p\nenv value address : %p\n%s\n", i++, env, *env, *env); 29 env++; 30 } 31 }

    上面这个程序fork出一个子进程,并且在子进程中修改了一个和增加了一个环境变量,另外有一个单独的函数show_env用来打印出此进程的环境表地址,所有环境变量字串,以及name=value字符串存储的地址。运行结果见下面3小节的图

    对unix进程来说,环境变量表是一个指针数组存在于进程空间中,每一个指针指向一个字符串,字符串是 name=value的形式,也就是这个环境变量的名字与值。而这个指针数组的起始地址就存在于一个全局变量 environ中, 在<unistd.h>头文件中有这样的声明

    /* NULL-terminated array of "NAME=VALUE" environment variables.  */
    extern char **__environ;
    #ifdef __USE_GNU
    extern char **environ;
    #endif

    先不管 __USE_GNU这个宏定义。可以看到unistd.h中声明了environ。当然unix并不鼓励我们直接使用environ, 而使用相应的系统调用来读取和修改环境变量表,虽然这在程序程面是可以的。

    2. 跟环境变量有关的系统调用

    在上面的函数中,用到了三个跟环境变量相关的系统调用, 另外再加上一个 unsetenv.

      #include<stdlib.h>
    1
    char * getenv(char * name); 2 int putenv(char * str); 3 int setenv(const char * name, const char * value, int rewrite); 4 int unsetenv(const char * name);

    这几个函数都是在 <stdlib.h>中声明的, 也就是要算属于C标准库的函数。其中putenv的参数是整个 name=value字符串。

    可能是shell对环境变量的使用比较大,所以shell有内置的命令以及专门的程序来操作环境变量。比如set, env, unset, export。但是我在使用的时候发现这几个东西,其中set,unset,export应该是shell内置的,env应该是一个单独的程序,发现有点混乱,export可以为shell增加环变量,而 unset让所有环境变量失效,这都只针对当前的shell进程,shell重新启动时,应该是从某个配置文件中读入默认的环境变量的.

    3。环境变量在进程空间的位置

    在最上面的那个程序中,show_env打印出了,环境表的地址,每个环境变量在表中的位置,以及字符串在内存中的位置。可以观查到的一个现象是从bash继承过来的环境表,也就是系统默认一个进程的环境表,不管是表还是那些字符串都是存储在高位地址的,实际上基本是在栈的最开始段。但是我若在这个表中增加了一项,整个表都会被移到低位地址中的堆中。上面那个程序的运行结果是

    可以看到父进程的环境表在进程空间的最高位部份,而子进程的增加了一条环境变量(wangyu=wangyu)则变到了低位地址中。在我的系统中(x86_64),虚拟地址空间是48位,也就是6个字节,6个字节需要12位16进制的数,从图中的第一个地址表示所使用的位数也可以看出。我的机子中在/proc/cpuinfo中有写到这样的信息   address sizes   : 36 bits physical, 48 bits virtual。   

    我通过运行上面程序的进程,然后在 /proc/pid/maps中查看(只能查看正在运行的进程,可以通过sleep(int)让进程暂时不退出),可以看到父进程的环境表是在栈中的(栈的顶端),而子进程的环境表是在小堆中的(small heap),父进程环境表中的指针所指向的name=value字符串也都在stack中,并且是在环境表的上面(环境表本身再高地址的地方)。而我在子进程中新增加的那个环境变量字符串“wangyu=wangyu”,则存在属于代码段(text)部份中(应该是代码区的全局数据段吧),地址比小堆(small heap)还要小

    下面是上面那个进程运行时其进程空间的布局,可以看到上面的两个env表的地址别在 [stack]区和[heap]区。   关于 x86_64进程空间的内存布局以后会详细写篇文章来学习。

  • 相关阅读:
    Android的webview的设置参数
    禁止RecycleView滑动
    Volley加载不出图片的问题
    LIstview滑动时不加载图片,停止时加载!
    【原创】设计模式开篇—面向对象的软件设计
    [原创]写给自己的总结—2014到2015
    【原创】开车分四个阶段的话,你属于哪个
    【原创】亲身经历的几次合同陷阱
    【转】程序员需谨记的8条团队开发原则
    【转】绩效考核的10大误区
  • 原文地址:https://www.cnblogs.com/livingintruth/p/2644542.html
Copyright © 2011-2022 走看看