1.环境变量
1)基本概念
a.环境变量一般是指在OS中用来指定OS运行环境的一些参数
b.当我们编写代码的时候,在执行链接的时候,我们不知道所连接的动态静态库在哪里,但是照样可以链接成功生成可执行程序,原因是相关环境变量帮助编译器进行查找。
c.环境变量在系统中通常具有全局特性
d.按照环境变量的生命周期来划分,Linux环境变量可分为两类:永久的(需要配置文件)以及临时的(使用export命令生命即可,变量在关闭shell时会失效)
2)常见环境变量
- PATH:指定命令的搜索路径
- HOME:指定用户的主工作目录(即用户登录到Linux系统中,默认的目录)
- HISTSIZE:指保存历史命令记录的条数
- SHELL:当前Shell,它的值通常是/bin/bash。
3)查看环境变量的方法
echo $环境变量名称
4)PATH的使用
我们使用makefile执行文件时,是./执行文件名,使用命令export PATH=$PATH:执行文件的路径
,就将执行文件的路径放到环境变量PATH中,然后直接输入执行文件名,便可以执行。
5)环境变量的相关路径
- echo:显示某个环境变量值
- export:设置一个新的环境变量
- env:显示所有环境变量
- unset:清除环境变量
- set:显示本地定义的shell变量和环境变量
6)环境变量的组织方式
环境是一个字符指针数组
,每个指针是指向一个以\0结尾的环境字符串,最后一个元素是NULL
7)获取环境变量的方法
a. 命令行第三个参数
#include<stdio.h>
int main(int argc,char *argv[ ],char *env[ ])
{
int i=0;
for(;env[i];++){
printf("%s\n",env[i]);
}
return 0;
}
b)通过第三方变量environ获取
environ指向环境变量表,没在任何头文件中,使用时,要用extern声明。
#include<stdio.h>
int main(int argc,char *argv[ ])
{
extern char **envision;
int i=0;
for(;environ[i];++){
printf("%s\n",environ[i]);
}
return 0;
}
c)通过getenv获取
#include<stdio.h>
#include<stdlib.h>
int main()
{
printf("%s\n",getenv("PATH");
return 0;
}
getenv函数
头文件:#include<sdlib.h>
函数:char *getenv(const char*name)
作用:用来获取name环境变量中的内容,name参数是环境变量的名称,如果该变量存在则返回指向该内容的指针,不存在则返回NULL。
putenv函数
头文件:#include<stdlib.h>
函数:int putenv(const char* string)
作用:用来改变环境变量的内容,如果环境变量存在,则变量内容会依照参数string改变,否则此参数内容成为新的环境变量
返回值:执行成功返回0,错误发生就返回-1
8)环境变量通常具有全局特性,可以被子进程集成下去。
#include<stdio.h>
#include<stdli.h>
int main()
{
char *env=getenv("MYENY");
if(env){
printf("%s\n",env);
}
return 0;
}
程序执行时,发现没有这个环境变量,但是执行命令export MYENV=“hello”,再次运行程序可以得到这个环境变量,说明环境变量可以被子进程继承export是把“变量”放到“环境”中,而环境变量是可以被子进程继承的。
2.进程地址空间
1)简单了解及图示
c语言时我们学习的空间分布图,用户使用的不是真正的物理内存,是虚拟的,不难理解,一个程序不可能使用完物理内存。
2)通过代码理解
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int g_val=0;
int main()
{
pid_t id=fork();
if(id<0)
{
perror("use fork");
exit(1);
} else if(id==0){//child
g_val=100;
printf("I am child:[%d],%d,%p\n",getpid(),g_val,&g_val); } else{//parent
printf("I am parent:[%d],%d,%p\n",getpid(),g_val,&g_val)
}
sleep(1);
return 0;
}
输出结果为:
i am parent:[5884],0,0x80497d8
i am child:[5885],100,0x80497d8
我们发现父子进程的地址相同所以这个地址不是物理地址,在Linux下我们称为虚拟地址,真正的物理地址由OS统一管理。用户一概看不到,OS必须负责将虚拟地址转换为物理地址。
3)同一个变量,地址相同,其实就是虚拟地址相同,内容不同就是被页表映射到不同的物理地址,如下图所示:
每一个进程都有一个PCB、虚拟地址空间、页表与维护映射关系。
当父进程创建一个子进程时,如果只读的化,父子进程的代码与数据是共享的,也就是说它们的虚拟地址空间与页表都是共享的,但是如果有一方试图修改数据,父子进程就以写时拷贝的方式数据各自私有一份,即虚拟地址空间与页表不同。
借助虚拟地址空间:可以实现资源独占,每个虚拟地址空间都是4G(32位),每个进程都可以认为它有4G的空间。