在此之前已经了解过了,进程的切换,进程优先级等进程的相关内容;那么在程序运行时,相关参数就怎么样进入到进程中的呢?
还有我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,为什么?
这就涉及到了本篇的主要内容,环境变量,环境变量表和命令行参数表;
基本概念
- 环境变量(environment variables)一般是指在操作系统用来指定操作系统运行环境的一些参数。
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
命令行参数
由上面的图可以知道,main函数的命令行 实际上是 先被bash切分,然后用于构建argv;
main函数的命令行参数,是实现程序不同子功能的方法;也是就说是 指令选项的实现原理。
(可以认为,之前不适用这种参数是因为不需要实现子功能)
环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
环境变量表
- 在储存的角度怎么理解环境变量呢?
bash 会形成一张表,也就是环境变量表。
- 环境变量最开始从哪里来的呢??
系统的相关配置文件中,如图
我们知道 十个用户登入Linux,就会有十个bash;那么这十个的bash 所存在的 系统的相关配置文件没有自己的修改,就是一样的;
要执行一个程序,必须先找到谁呢?
我们知道 env 打印的就是 bash 内部的环境变量表。
bash 内部会形成一张表,环境变量表;环境变量就存在 bash 中。以 ls -a -b 为例,输入这些一定是 bash 先拿到;
在 bash 的环境变量表中找 ls 的环境变量,找 bash 创建的命令行参数表。
因此
对命令行解析,得到命令行参数表,再根据 命令行参数表 查找环境变量表。
所以
必选先找到bash,在根据bash内部环境变量表 PATH(环境变量)来找这个 可执行文件;
所以系统中存在环境变量,来帮助找到目标二进制文件;
存在环境变量 PATH,然后通过这个 系统中搜索指令的搜索路径,就能找到对应的目标二进制文件;
那么为什么我们写的二进制文件需要加 ./ 而 系统二进制文件不需要 ./呢?
因为 系统的二进制文件是 存在于对应的 路径中;如图
系统可以通过 环境变量 PATH 找到对应的 二进制文件;而我们的 二进制文件 的对应路径不在存在于这个 环境变量中;
所以只要把 对应二进制文件的路径 加到这个环境变量中即可;
方法1
通过代码如何获取环境变量
操作
- echo: 显示某个环境变量值
- export: 设置一个新的环境变量
- env: 显示所有环境变量
- unset: 清除环境变量
- set: 显示本地定义的shell变量和环境变量
具体其他操作可以自行搜索
代码
- 命令行第三个参数
这个方法其实就,从父进程(bash)获取环境变量;
因此我们也可以知道 环境变量是可以被子进程的 继承的;
- 通过第三方变量environ获取
注意:
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
- getenv
如果我想写一个程序,只能我执行,其他人一律不让执行!
看如下代码
为什么要使用这些变量呢?
在VS 中 如果不使用这些变量,可能会报错;强转一下 就相当于应用了,就防止报错了;
main函数的多功能是如何实现的
通过查看反汇编可以发现 (objdump -S code)
main函数的开头应该是类似于这样的代码:
环境变量通常是具有全局属性的
环境变量通常具有全局属性,可以被子进程继承下去
两个概念
- 本地变量和环境变量
上面这个就是本地变量,不会被子进程继承;
- 我们的环境变量在那里面?当然是bash
为什么export这个子进程能导入到bash这个父进程里面呢?
export是 内建命令 built-in command
不需要创建子进程,而是让 bash 自己亲自执行
bash 自己调用函数,或者系统调用完成!
如果不明白的话,进程控制中有详细 的对内建命令的解释;