1.环境变量概念
环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:在编写C/C++代码的时候,在链接的时候,从来不知道我们所链接的动静态库在那里,但是照样可以链接成功,生成可执行程序,就是因为有相关的环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统中通常具有全局特性
2.命令行参数
main函数是有参数的,一个为argc整型和char*的argc字符串数组,这个字符串数组内容是我们输入的字符串,bash会切分输入的字符串然后放到数组里面,而argc整型就是表示有多少个元素存储在这个数组里面,所以输入什么就会打印出什么,这些被存储在数组的就是命令行参数。


cpp
1 #include<stdio.h>
2
3
4 int main(int argc,char* argv[])
5 {
6 for(int i=0;i<argc;i++)
7 {
8 printf("%s\n",argv[i]);
9 }
10 return 0;
11
12 }
命令行参数的应用
通过argv数组得到输入的字符串内容,进行条件判断执行不同的子功能,由此可知输入的命令。如ls -la也一样,通过命令行参数执行不同的功能(命令也是由C/C++写的)

cpp
1 #include<stdio.h>
2 #include<string.h>
3
4 int main(int argc,char* argv[])
5 {
6 if(argc!=2)
7 {
8 printf("12test [-a|-b|-c]\n");
9 }
10 else
11 {
12 if(strcmp(argv[1],"-a")==0)
13 printf("功能1\n");
14 else if(strcmp(argv[1],"-b")==0)
15 printf("功能2\n");
16 else
17 printf("功能3\n");
18 }
19
20
21 return 0;
22 }
~
3.PATH环境变量
为什么自己写的程序要有./才行,而ls -al却可以直接执行
因为要执行自己写的代码需要被找到才可以进行操作,而Linux的命令是提前就写好在里面了,因为系统有环境变量来帮助系统找到目标二进制文件,所以可以直接执行,自己写的文件要./表示在此目录下有这个可执行文件。bash会通过PATH这个环境变量来找,PATH是搜索指令的默认搜索路径。

4.查看PATH
echo $PATH
可以看到显示的绝对路径,也就是说不加./的命令系统会根据PATH提供的路径去找,如果找完这些路径没有找到则就会说命令没找到,如果把我们写的代码路径加进去则也不用加./也能执行了。
(PATH=路径可以进行替换,关掉XShell后重启会恢复或者PATH=$PATH:路径进行增加而不是替换)
cpp
root@iZbp1be068ksa92vuf0kbdZ:~/zym/mytest# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
5..常见的环境变量
PATH:指定命令的搜索路径
HOME:指定用户的主工作目录(即用户登录到Linux系统中时默认的目录)
SHELL:当前的Shell,它的值通常是/bin/bash
3.查看环境变量方法
环境变量是变量,所以是变量名=内容
env

6.理解环境变量
环境变量存储
bash会形成一张表,环境变量表,表示一个数组存储指针指向环境变量

环境变量最开始来自配置文件
在家目录下有.bash_profile和.bashrc俩个配置文件,会从这里得到环境变量的信息,在配置文件里面会有PATH环境变量,如果把自己写的代码所在路径加入到配置文件里面,则就算重启也会保存住。

7..和环境变量相关的命令
1.echo +$环境变量名字:显示某个环境变量的值
2.export:设置一个新的环境变量
3.env:显示所有环境变量
4.unset:清除环境变量
5.set:显示本地定义的shell变量和环境变量
本地变量
创建一个本地变量i,set命令可以找到i在里面,本地变量不会被子进程继承,只在bash内部使用


8..环境变量的组织方式

每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以'/0'结尾的环境字符串
通过envision查看环境变量
cpp
1 #include<stdio.h>
2
3 extern char** environ;
4 int main()
5 {
6
7
8
9 for(int i=0;environ[i];i++)
10 {
11 printf("environ:%s\n",environ[i]);
12 }
13 return 0;
14 }
~
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头⽂件中,所以在使⽤时 要⽤
extern声明。
通过命令行第三个参数获取环境变量
cpp
1 #include<stdio.h>
2
3 extern char** environ;
4 int main(int argc,char* argv[],char* env[])
5 {
6
7
8
9 for(int i=0;env[i];i++)
10 {
11 printf("env:%s\n",env[i]);
12 }
13 return 0;
14 }
~
~
通过系统调用获取环境变量
cpp
1 #include<stdio.h>
2 #include<stdlib.h>
3 extern char** environ;
4 int main(int argc,char* argv[],char* env[])
5 {
6
7
8
9
10
11
12 printf("%s\n",getenv("PATH"));
13 return 0;
14 }
~
9.环境变量通常具有全局特性
父进程的环境变量可以被子进程继承,也可以被孙子进程继承往后等。
export命令如果是会创建进程,那么在子进程创建的环境变量为什么在父进程也有,进程之间不是独立的吗,是因为export是内建命令,不需要创建子进程,而是让bash亲自指向,bash自己调用函数,或者是系统调用完成
10.补充:
程序一开始不是从main函数开始而是start开始
程序开始时会扫描main函数的参数有多少个,不同的参数个数决定对应哪一种

11.程序地址空间

代码验证:
通过已知的验证未知的
cpp
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_unval;
int g_val = 100;
int main(int argc, char *argv[], char *env[])
{
const char *str = "helloworld";
printf("code addr: %p\n", main);
printf("init global addr: %p\n", &g_val);
printf("uninit global addr: %p\n", &g_unval);
static int test = 10;
char *heap_mem = (char*)malloc(10);
char *heap_mem1 = (char*)malloc(10);
char *heap_mem2 = (char*)malloc(10);
char *heap_mem3 = (char*)malloc(10);
printf("heap addr: %p\n", heap_mem); //heap_mem(0), &heap_mem(1)
21 printf("heap addr: %p\n", heap_mem1); //heap_mem(0), &heap_mem(1)
22 printf("heap addr: %p\n", heap_mem2); //heap_mem(0), &heap_mem(1)
23 printf("heap addr: %p\n", heap_mem3); //heap_mem(0), &heap_mem(1)
24
25 printf("test static addr: %p\n", &test); //heap_mem(0), &heap_mem(1)
26 printf("stack addr: %p\n", &heap_mem); //heap_mem(0), &heap_mem(1)
27 printf("stack addr: %p\n", &heap_mem1); //heap_mem(0), &heap_mem(1)
28 printf("stack addr: %p\n", &heap_mem2); //heap_mem(0), &heap_mem(1)
29 printf("stack addr: %p\n", &heap_mem3); //heap_mem(0), &heap_mem(1)
30
31 printf("read only string addr: %p\n", str);
32 for(int i = 0 ;i < argc; i++)
33 {
34 printf("argv[%d]: %p\n", i, argv[i]);
35 }
36 for(int i = 0; env[i]; i++)
37 {
38 printf("env[%d]: %p\n", i, env[i]);
39 }
40
41 return 0;
42}

虚拟地址
cpp
#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;
}

可以看到子进程和父进程地址是一样的,但是gval的值不一样,如果是物理空间就不对了,一个变量在一块物理空间上不能对应俩个值,所以是虚拟的空间