为什么函数返回值, 会被外部拿到呢?
我们的返回值其实是先给了寄存器, 再由寄存器给外部
计算机怎么知道我们的当前进程,执行到哪行代码了?
cou内有一个程序寄存器(pc
指针 || eip), 他会记录当前进程正在执行的指令的下一行的地址。当cpu 执行完当前代码后, 就会去pc里找下一行代码, 而pc又会自动去记录下一行的地址
cpu内的的寄存器里保存的是进程的相关数据
(对其进行访问和修改), 进程在从CPU
上离开的时候,要将自己的上下文数据保存好
甚至是直接带走
,保存的目的是是为了未来再执行的时候恢复现场
所以 进程在被切换的时候要经历两个过程
1 保存上下文
2 恢复上下文
环境变量
基本概念
先讲一点实例
为什么我们在使用which
时系统能帮我们找到他在哪?
PATH
以:
为分隔符, 存储了很多的路径, 这些路径, 通常都是我们在执行指令时候, 系统去查找指令的地方。
我们称这个环境变量为Linux 中的指令搜索路径
;
如果我们将我们自己编写的程序放进这个环境变量包含的目录里, 或者是, 将其所在的地址设置进环境变量里, 我们就可以将执行指令一样去执行我们的程序了
这里我们只演示第二种
如何往PATH添加环境变量
注意
:等于是直接覆盖, 所以如果不加上$PATH
的话, 原本设置的环境变量就会被覆盖,其中,$PATH
就是环境变量里包含的内容
成功添加进去了
发现现在运行可执行程序不需要带路径了;
用which
也能直接找到我们的可执行程序了
如果我们将PATH覆盖了, 那么系统中大部分的指令都跑不了了(无法像平常一样使用)
如果你不小心覆盖了PATH, 不用着急, 这个是内存级别的,把Xshell 关掉重开就好了
HOME
我们发现,不同用户的HOME
变量是不同的;
SHELL
这个对应的是当前shell
所对应的可执行程序
env
(environment)命令
env命令能查看当前进程以及bash进程从系统里所继承下来的环境变量
getenv()
将对应环境变量的名字传过去, 该函数会返回其对应的内容
在换一个例子
我们换成root来执行这段代码
发现结果变成了root
所以我们得出结论:
有了环境变量的存在, 对于不同的账号, 程序内部就可以通过环境变量, 获得不同的信息。
对权限的新认知
在这里我们就可以对权限有了新的认知
系统是如何知道我们是谁, 从而给我们设置对应的权限呢?
就是靠的环境变量, 有了他的存在, 系统就可以认识我们
并给予我们对应的权限;
什么是环境变量
:
环境变量是系统提供的name = value
形式的变量, 不同的环境变量, 有不同的用户, 通常具有全局属性;
命令行参数
int main(int argc, char* argv[]) {
}
这两个参数就叫命令行参数
其中argc
表示的是argv
里包含的元素的个数
我们将其打印出来看看
可以看到只有一个./mycmd
但是当我们在加上选项后, 发现选项是被记录进了argv
里的
// 到这里或许我们就能明白为什么有些命令可以带选项
为什么要这么干呢?
命令行参数的作用
:
为指令、工具、软件等提供命令行选项的支持!
但是main
函数只会有这两个参数吗?
还可以, int main(int argc, char* argv[], char*env[]
)
getenv()
只能帮我们获取对应的某一个环境变量, 而env
里包含的是这个程序启动时包含的所有环境变量
他与argv
一样都是图中所示的向量表
所以我们的c/c++代码会有两张核心向量表
1.命令行参数表
2.环境参数表
我们将环境变量表打印出来看看
可以看到, 打印出了和 env
指令一样的表
这是因为当我我们在用./
运行程序时, 我们的进程是bash
的子进程, 换句话说, 子进程是可以继承父进程环境变量的信息的
这也就是为什么环境变量通常具有全局属性
怎么验证环境变量能被子进程继承
下去呢?
自己设置环境变量
我们直接这样是没法设置环境变量的, 但他也不是直接不存在了
我们还是可以这样查看到他的, 只是他没在环境变量列表里, 因为直接在命令行里定义的这种变量我们称之为本地变量
export
设置环境变量
这样我们就设置了一个自己的环境变量
我们刚刚的操作只是改变了bash
的环境变量对我们的程序并没有做手脚
运行一下发现, 我们的进程还是拿到了这个变量
所以,就证明了 子进程确实是可以进程父进程的环境变量
我们可以将某种规则定义在bash的环境变量里, 这样他所有的子进程就都会遵守这个规则, 这也就是为什么我们的系统中能定义权限这种东西而所有的指令都会去遵守他呢?
unset
取消环境变量
当我们取消掉bash
上的这个环境变量后发现程序也找不到他了。
environ 查看环境变量
我们不一定需要通过命令行参数来获取环境变量, 通过这个参数我们我们一样能获取到, 因为这个参数是直接指向父进程的环境变量表
的
本地变量
我们知道, 直接这样定义的变量是本地变量, 我们是无法在env
中看到他,
set
set可以看到你当前系统重的所有变量, 包括环境变量和本地变量
本地变量是不会被子进程继承
的, 他只会在本bash
内部有效。
我们切成root
后发现刚刚定义的变量没了
我们写这么一段程序
但是程序找不到这个变量
我们将其变成环境变量后就可以被程序找到了
内建命令
由于这个问题, 我们需要对前期的一个概念进行纠正;
命令行上执行的指令, 不一定都要创建子进程
命令分为两批命令
1.常规命令--通过创建子进程完成的
2.内建命令--bash不创建子进程,而是由自己亲自完成, 类似于bash调用了自己写的或系统提供的函数
举几个内建命令的例子:
1 echo
2 cd
如果cd不是内建命令, 那么更改的将会是子进程的工作目录, 而不是父进程本身的。
chdir
更改工作目录的接口
我们写这么一个程序来模拟bash
但是发现他并不能帮我们更改工作目录, 原因是我们执行程序时会创建bash子进程
所以其实更改的是子进程的工作目录
验证一下
我们将子进程的工作目录改到根目录上
可以看到一开始子进程的工作目录在文件所属的目录下
更改后处于了根目录