环境变量
基本概念
*环境变量一般是指在操作系统中用来制定操作系统运行环境的一些参数,如:我们在编写c/c++代码的时候,在连接的时候,我们从来不知道所连接的动态静态库在哪里,但是照样可以连接成功,生成可执行程序,原因就是有相关的环境变量帮助编译器进行查找
*环境变量通常具有某些特殊用途,在系统红通常具有全局特性
常见的环境变量
PATH* :指定命令的搜索路径
HOME* :指定用户的主工作目录
HISTSIZE* :指保存历史命令记录的条数
SHELL* :当前shell,它通常是/bin/bash
查看环境变量的方法
echo $NAME
和环境变量相关的命令
1 echo:显示某个环境变量值
2 export:设置一个新的环境变量
3 env:显示所有的环境变量
4 unset:清楚环境变量
5 set:显示本地定义的shell变量和环境变量
通过代码如何获得环境变量
1 通过命令行的第三个参数
int main(int argc,char *argv[],char *env[])
{
int i=0;
for(;env[i].i++)
{
printf("%s\n",env[i]);
}
return 0;
}
2 通过第三方变量environ获取
int main(int argc,char *argv[])
{
extern char **environ;
int i=0;
for(;environ[i];i++)
{
printf("%s\n",environ[i]);
}
return 0;
}
//libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件里面,所以在使用的时候,要加 extern声明
另外,我们还可以通过系统调用来获取或者设置环境变量
int main()
{
printf("%s\n",get("PATH"));
return 0;
}
环境变量有通常具有全局属性,可以被子进程继承下去
int main()
{
char *env=getenv("MYENV");
if(env)
{
printf("%s\n",env);
}
return 0;
}
直接查看发现没有结果,说明了该环境变量根本就不存在,接下来我们进行下面的操作:
导出环境变量:export MYENV=”hello world”
再次运行程序的时候,发现结果有了!说明:环境变量是可以被子程序继承下去的
程序地址空间
直接上代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int g_val = 0;
int main()
{
pid_t id =fork();
if(id<0)
{
perror("fork");
return 0;
}
else if(id==0)
{
printf("chile[%d]:%d:%p\n",getpid(),g_val,&g_val);
}
else
{
printf("parent[%d]:%d:%p\n",getpid(),g_val,&g_val);
}
sleep(1);
return 0;
}
我们发现,输出出来的变量值和地址是一模一样的,接下来我们对变量进行修改
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int g_val = 0;
int main()
{
pid_t id =fork();
if(id<0)
{
perror("fork");
return 0;
}
else if(id==0)
{
g_val = 100;
printf("chile[%d]:%d:%p\n",getpid(),g_val,&g_val);
}
else
{
printf("parent[%d]:%d:%p\n",getpid(),g_val,&g_val);
}
sleep(1);
return 0;
}
在这里我们可以看到,父子进程输出的地址还是一致的,但是变量内容不一样了
由此我们可以得出以下结论:
1,变量内容不一样,所以父子进城输出的变量绝对不是同一个变量;
2,但是他们的地址是一样的,那就说明了,该地址绝对不是物理地址
3,在Linux地址下,这种地址叫做虚拟地址
我们在用c/c++语言所看到的所有地址,都是虚拟地址!!!
物理地址,用于一概看不到,由os统一管理
os必须负责将虚拟地址转换成物理地址
早期内存管理机制
要运行一个程序,会把这些程序全都装入内存。
当计算机同时运行多个程序的时,必须保证这些程序用到的内存总量要小于计算机实际物理内存的大小。
进程地址空间不隔离。由于进程都是直接访问物理内存,所以恶意程序就可以随意的修改别的进程的内存数据,以达到破坏的目的。
内存使用效率低。
程序运行的地址不确定。
现在采取分段的方式
在编写代码的时候,只要指明了所属段,代码段和数据段中出现的所有的地址,都是从零开始,映射关系完全由操作系统维护。
CPU将内存分成了不同的段,于是指令和数据的有效地址并不是真正的物理地址,而是相对于段首地址的偏移地址。
这样的效果是
因为段寄存器的存在,是的进程的地址空间得以隔离,越界问题很容易被判定出来
实际代码和数据中的地址,都是偏移量,所以第一条指令可以从0地址开始,系统会自动进行转化映射,也就解决了程序运行的地址不确定问题。
但是,分段并没有解决性能问题,在内存空间不足的情况下,依旧要换入换出整个程序或者整个段,无疑要造成内存和硬盘之间大量拷贝数据的情况,进而导致性能问题
上面的代码就说明问题同一个变量地址相同,其实就是虚拟地址相同,内容不同其实就是被页表映射到了不同的物理地址