环境变量
1.概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
思考:为什么Linux下的命令行指令可以直接执行,不需要带路径,而我们写的二进制程序 需要带路径才能执行?
答案:是因为这些命令的路径已经添加在系统环境变量中了。
2.常见的环境变量
PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。
3.查看环境变量的方法
echo $NAME //NAME:你的环境变量名称
4.相关的命令
echo:显示某个环境变量的值。
export:设置一个新的环境变量。
env:显示所有环境变量。
unset:清除环境变量。
set:显示本地定义的shell变量和环境变量。
5.环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。
6.通过代码获取环境变量
通过命令行第三个参数获取
#include<stdio.h>
int main(int argc,char *argv[],char*env[])
{
for(int i=0;env[i];++i)
{
printf("%s\n", env[i]);
}
return 0;
}
通过第三方变量获取environ
#include <stdio.h>
int main(int argc, char *argv[])
{
extern char **environ;
int i = 0;
for(; environ[i]; i++){
printf("%s\n", environ[i]);
}
return 0;
}
lib中定义的全局变量environ 指向环境变量表,environ没有包含在任何头文件中,所以使用的时候需要 extern声明。
7.通过系统调用获取,设置环境变量。
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}
8.环境变量的全局属性
环境变量通常具有全局属性,可以被子进程继承下去
进程地址空间
32位平台
先给出一个概念,上面程序的地址空间,实际为虚拟地址空间。
#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
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
else{ //parent
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
我们发现,输出出来的变量值和地址是一模一样的,很好理解呀,因为子进程按照父进程为模版,父子并没有对变量进行进行任何修改。可是将代码稍加改动:
#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;
}
可以发现此时父子进程中的 g_val输出不一致了,但是地址确还是一样。
可以得到以下结论。
变量内容不一样,所以父子进程输出的变量绝对不是同一个变量。
但地址值是一样的,说明,该地址绝对不是物理地址!
在Linux地址下,这种地址叫做虚拟地址
我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理,OS负责将虚拟地址转化成物理地址。
看上图,每个进程都有自己独立的进程地址空间(虚拟地址空间),一个进程包含数据和代码两部分,其中数据几位 task_struct的进程数据结构管理,通过一个指针 指向进程地址空间,进程在编译好,运行之前其内部已经包含地址,此地址为虚拟地址,通过页表映射的方式,在物理地址中开辟空间。