环境变量+程序地址

 一、环境变量
1、环境变量一般指在OS中用来指定OS运行环境的一些参数。
     环境变量是变量,有变量名和变量内容。
    环境变量通常具有某些特殊用途,在系统中通常具有全局特性
2、常见的环境变量
  • PATH*: 指定命令的搜索路径
  • HOME*: 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
  • HISTSIZE*: 指保存历史命令记录的条数
  • SHELL*: 当前Shell,它的值通常是/bin/bash。
3、查看环境变量
     env    所有的环境变量
     echo   【echo  $HOME】
     getenv()  【参数为环境变量名字符串】
4、PATH环境变量
 /usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/hb/bin
    搜索时,现在第一个:号前搜索,搜不到在去第一个:和第二个:之间去搜索……最后找不到会报错
5、添加环境变量的内容
    PATH=$PATH:/home/hb/bit-code/31_class/linux/2_class
    【上述命令可以添加,但不建议,建议采用下面的命令】
    export PATH=$PATH:/home/hb/bit-code/31_class/linux/2_class
    【不仅赋值,还要导出环境变量】
6、HOME环境变量
    当前用户的主工作目录
    /home/du
    /root
    【cd ~  即转到当前用户的主工作目录   =cd $HOME
7、HISTSIZE
    能够保留的历史命令行数  
8、SHELL环境变量
    shell是所有外壳程序的总和
    用户通过shell与OS联系
    bash是shell的一种
    【echo $SHELL         /bin/bash】
9、 创建一个新的环境变量
eg1:
MYENV_VAL=4321abcd      【直接新建变量】
env | grep MYENV_VAL     【输出错误,MYENV_VAL不存在。  env只输出环境变量】
echo $MYENV_VAL       【可以输出,得到4321abcd】
set   【set不仅输出环境变量也输出其他符号】
eg2:
export MYENV_VAL
env | grep MYENV_VAL     【可以输出,结果为MYENV_VAL=4321abcd】
echo $MYENV_VAL       【可以输出,得到4321abcd】
set | grep MYENV_VAL    【得到MYENV_VAL=4321abcd】
【注:export可以将本地变量转变为环境变量,eg1中MYENV_VAL未经export,所以只是本地变量,不能被env展示出】
【本地变量不能被子进程拿到,但从bash开始(包括bash)其下的所有进程都可以看到环境变量】
10、unset
     unset MYENV_VAL  取消环境变量

二、程序地址空间
1、虚拟地址空间(进程地址空间)!=程序地址空间 
2、c语言打出的地址是虚拟地址
     虚拟地址最终要转化为物理地址
3、例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
    pid_t id = fork();
    if(id < 0){
        perror("fork");
        return 0;
    }
    else if(id == 0){ //child,⼦子进程肯定先跑完,也就是⼦子进程先修改,完成之后,⽗父进程再读取
        g_val=100;
        printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }else{ //parent
        sleep(3);
        printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
    sleep(1);
    return 0;
}
结果:
//与环境相关,观察现象即可
child[3046]: 100 : 0x80497e8
parent[3045]: 0 : 0x80497e8
我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:
  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量但地址值是一样的,说明,该地址绝对不是物理地址!
  • 在Linux地址下,这种地址叫做 虚拟地址
  • 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址用户一概看不到,由OS统一管理。过程图见下:

4、虚拟地址空间在linux内核上其实也就是一个结构体,叫做m_struct。
    虚拟地址空间对物理内存有保护作用。
5、创建一个进程需要做的事:
  • PCB
  • m_struct
  • 页表(用户级页表,每个进程都有一个)

     
三、vfork函数
    也是用来创建子进程,但是
    vfork用于创建一个子进程,而子进程和父进程 共享地址空间。fork的子进程具有独立地址空间
    vfork 保证子进程先运行,在它调用exec或(exit)之后父进程才可能被调度运行。
关于共享地址空间:
eg1:
int glob = 100;
int main( void )
{
    pid_t pid;
    if ( (pid= fork() ) == -1 ) perror("fork"),exit(1);
    if (pid == 0 ) { // child
        printf("before:child glob %d\n", glob);
         glob = 200;
        printf("after:child glob %d\n", glob);
        sleep(3);
        exit(1);
    } else { // parent
        printf("parent glob %d\n", glob);
    }
    return 0;
}
//结果:
[root@localhost linux]# ./a.out
parent glob 100
[root@localhost linux]#child glob 100
child glob 100
eg2:
int glob = 100;
int main( void )
{
    pid_t pid;
    if ( (pid= vfork()) == -1 ) perror("fork"),exit(1);
    if (pid == 0 ) { // child
         printf("before:child glob %d\n", glob);
         glob = 200;
        printf("after:child glob %d\n", glob);
        sleep(3);
        exit(1);
    } else { // parent
        printf("parent glob %d\n", glob);
    }
    return 0;
}
//结果:
[root@localhost linux]# ./a.out
before:child glob 100
after:child glob 200
parent glob 200  //3秒后输出

【补:】
(1)main函数正确退出返回0,错误退出返回不同的退出码
(2)echo $?   查询退出码(只保存离其最近的一条命令的退出码)
(3)在当前程序的任何一个地方使用exit都会使进程终结,main函数不再返回return的值,而返回exit的值。eg: eixt(123);……return 0;,则退出码为123。
(4)调用exit()退出和_exit退出的区别是:exit()在结束前会做一些收尾工作,而_exit会强制退出。


















猜你喜欢

转载自blog.csdn.net/gunqu_d/article/details/80528970