珠海网站建设熊掌号,怎样免费做一个网站,产品包装设计素材网站,网站程可以自己做吗一、环境变量
#xff08;一#xff09;概念
环境变量(environment variables)#xff1a;系统当中用做特殊用途的系统变量。 如#xff1a;我们在编写C/C代码的时候#xff0c;在链接的时候#xff0c;从来不知道我们的所链接的动态静态库在哪里#xff0c;但是照样可…一、环境变量
一概念
环境变量(environment variables)系统当中用做特殊用途的系统变量。 如我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。 环境变量通常具有某些特殊用途还有在系统当中通常具有全局特性。 子进程默认会复制拥有与父进程相同的环境变量。
二常见环境变量
PATH : 指定命令的搜索路径 HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录) SHELL : 当前Shell,它的值通常是/bin/bash。
三查看环境变量方法
echo $NAME NAME:你的环境变量名称 指令 env——显示所有环境变量
四和环境变量相关的命令
echo: 显示某个环境变量值 export: 设置一个新的环境变量export aaaa env: 显示所有环境变量 unset: 清除环境变量rm只是普通的文件操作指令无法删除环境变量 set: 显示本地定义的shell变量本地变量和环境变量 1.echo: 显示某个环境变量值 2.export : 导出环境变量 3.env : 显示所有环境变量 4.unset 删除环境变量 5.set查看本地定义的shell变量本地变量和环境变量 五和环境变量相关的命令
基本指令也是程序为什么我们的代码程序运行要带路径而系统的指令不用带路径? 比如使用指令lspwd时直接使用即可使用自己的myproc 可执行程序时gcc -o mproc.c myproc 需要./myproc.c 答系统中是存在相关的环境变量保存了程序的搜索路径的! 比如执行 ls 这个可执行程序时系统会在PATH中一个一个搜索在特定路径系统所有命令都在usr/bin路径下下可以找到ls就可以执行。 系统中搜索可执行程序的环境变量叫做 PATH !
1.如何让自己的程序不带路径也可以执行
把自己的程序拷贝进环境变量中就可以直接myproc执行程序了拷贝的过程就是安装软件但是不建议这样做本身我们的软件就没什么意义会污染系统删除卸载。 把myproc自己的文件加入环境变量PATH中export PATH$PATH:路径相当于把PATH中的路径改成PATH和myproc的路径。 错误示范如果直接 export PATH路径 会覆盖环境变量PATH的原有路径这里pwd还能用lstop什么的就不能用了
# 二、常见的环境变量
XDG_SESSION_ID299733
TERM_PROGRAMvscode
HOSTNAMEVM-24-7-centos
TERMxterm-256color
SHELL/bin/bash 显示shell所在路径
HISTSIZE3000 历史能够记录自己敲过的命令条数
SSH_CLIENT111.18.128.241 7177 22 ip地址
TERM_PROGRAM_VERSION1.78.2 版本
USERroot/ 用户名
VSCODE_GIT_ASKPASS_MAIN/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/extensions/git/dist/askpass-main.js
LOGNAMEroot
MAIL/var/spool/mail/root
PWD/root/new/add.ringqueue PWD当前用户所处路径
LANGen_US.utf8 支持的编码格式现在支持的是UTF8
VSCODE_GIT_ASKPASS_EXTRA_ARGS
HOME/root 代表不同用户的家目录
SHLVL5
VSCODE_GIT_IPC_HANDLE/run/user/0/vscode-git-d20790e3d3.sock
SSH_CONNECTION111.18.128.241 7177 10.0.24.7 22
VSCODE_IPC_HOOK_CLI/run/user/0/vscode-ipc-729d4afb-0a8a-48d3-848b-da318c83e93a.sock
LESSOPEN||/usr/bin/lesspipe.sh %s
BROWSER/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/bin/helpers/browser.sh
PROMPT_COMMAND__vsc_prompt_cmd_original
VSCODE_GIT_ASKPASS_NODE/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/node
GIT_ASKPASS/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/extensions/git/dist/askpass.sh
XDG_RUNTIME_DIR/run/user/0
HISTTIMEFORMAT%F %T
COLORTERMtruecolor
OLDPWD/root/new
_/usr/bin/env一HOSTNAME——显示主机名
[rootVM-24-7-centos add.ringqueue]# echo $HOSTNAME
VM-24-7-centos二SHELL—— 显示shell所在路径
三HISTSIZE——历史能够记录自己敲过的命令条数
四HOME——代表不同用户的家目录
三、环境变量和局部(普通)变量
环境变量系统当中用做特殊用途的系统变量。 命令行变量分两种:
一普通变量在env查不到
二环境变量(全局)在env能查到
环境变量具有全局属性环境变量是会被子进程继承下去的! ! 所谓得本地变量本质就是在bash内部定义的变量不会被子进程继承下去!
四、环境变量的C、C获取方式
一问题1main函数可以带参数吗?最多可以带多少?
可以实际是三个。
1. 先说main函数的前两个参数
main函数的前两个参数分别是下图所示这两个参数我们称为命令行参数 int main(int argc,char *argv[]) { // 数组个数 数组
}
2.argv[]中放什么呢
我们给main函数传递的前两个参数 argcchar* argv[] 称为 命令行参数传递的是命令行中输入的程序名和选项比如命令行输入了./myproc -a -b -cargc对应就是4argv[ ] 中传入了这4个字符串argv[0] “./myproc”argv[1] “-a”argv[2] “-b”argv[3] “-c”argv[4] “NULL”指针数组以NULL结尾。 给命令行参数传程序名和选项意义是什么我们通过实现一个命令行版的计算器来理解
二实现一个命令行版的计算器
我们要实现的功能 执行 ./myproc -a 10 20 要实现 102030; 执行 ./myproc -s 10 20 要实现 10-20-10
// makefile
myproc:myproc.cg -o $ $^ -stdc11 -lpthread
.PHONY:clean
clean:rm -f myproc
// main.c
#include stdio.h
#include unistd.h
#include string.h
#include stdlib.hint main(int argc,char *argv[])
{if (argc ! 4){//如果用户输入不对打印使用手册-a加法-ssubtract减法-m乘法-d除法printf(Usage: %s [-a|-s|-m|-d] one_data two_data\n, argv[0]);return 0;}int x atoi(argv[2]); //atoi把字符串转为整数int y atoi(argv[3]);if (strcmp(-a, argv[1]) 0) //如果输入-a就是加法{printf(%d%d%d\n, x, y, x y);}else if (strcmp(-s, argv[1]) 0) //如果输入-s就是减法{printf(%d-%d%d\n, x, y, x - y);}else if (strcmp(-m, argv[1]) 0) //如果输入-m就是乘法{printf(%d*%d%d\n, x, y, x * y);}else if (strcmp(-d, argv[1]) 0 y ! 0) //如果输入-d就是除法{printf(%d/%d%d\n, x, y, x / y);}else{//输入错误说明不会用还是打印使用手册printf(Usage: %s [-a|-s|-m|-d] one_data two_data\n, argv[0]);}return 0;
}1.给命令行参数传程序名和选项意义是什么
答同一个程序通过传递不同的参数让同一个程序有不同的执行逻辑 / 执行结果。 这就解释了指令中那么多选项的由来和起作用的方式Linux系统中会根据不通的选项让不同的命令可以有不同的表现 这就解释了我们平时输入的指令传入了哪里!
三命令行可以带第三个参数 char *env[]环境变量
1.每个进程是会被传入环境变量参数的环境变量传给env[] 。
#includestdio.h int main(int argc,char* argv[],char* env[]) { // 存环境变量的指针数组以NULL结尾所以到NULL时for循环结束 for(int i0;env[i];i) { printf(“env[%d]:%s\n”,i,env[i]); } return 0; }
2.C语言中函数无参也是可以传参的只不过实参没用上
但是如果是int fun(void) 就不可以传参。 这就解释了我们可以直接给main()函数传参的原因
四通过代码获取环境变量的三种方式
1.C语言获取环境变量的第一种方法
#includestdio.h
int main(int argc,char* argv[],char* env[])
{
// 存环境变量的指针数组以NULL结尾所以到NULL时for循环结束for(int i0;env[i];i)
{printf(env[%d]:%s\n,i,env[i]); }
return 0;
}2.通过第三方变量environ获取
C语言给我们提供了一个全局变量environ。
#include stdio.h
#include unistd.h
#include string.h
#include stdlib.hint main() {extern char** environ;for (int i 0; environ[i]; i ) {printf(%d : %s \n,i,environ[i]);}return 0;
}3.getenv——获取环境变量的接口
通过环境变量名直接获得环境变量的内容。
#include stdio.h
#include unistd.h
#include string.h
#include stdlib.h
int main() {char *val getenv(PATH);printf(%s\n,val);return 0;
}五、程序地址空间
一概念
程序地址空间不是内存! 程序地址空间进程地址空间是操作系统上的概念! 堆栈相对而生。 堆区向地址增大方向增长 栈区向地址减少方向增长 我们一般在C函数中定义的变量通常在栈上保存那么先定义的一定是地址比较高的 如何理解static变量 函数内定义的变量用static修饰本质是编译器会把该变量编译进全局数据区! 二感知地址空间的存在
函数内定义的变量用static修饰本质是编译器会把该变量编译进全局数据区! 父子进程共享全局变量。
#includeunistd.h
#includecstdio
int g_val 100;
int main() {pid_t id fork();if (id 0) {int flag 0;while (true) {printf(i am son %d, ppid : %d, g_val : %d, g_val : %p\n\n,getpid(),getppid(),g_val,g_val);sleep(1);flag ;if (flag 5) {g_val 200;printf(全局数据我已经改了请你注意查看\n);}}}else {while(true) {printf(i am father %d, ppid : %d, g_val : %d, g_val : %p\n\n,getpid(),getppid(),g_val,g_val);sleep(2); }}return 0;
}fork创建子进程父子进程同时运行若在子进程中第5秒改了全局变量g_val的值会发现
父子进程读取同一个变量(因为地址一样!)但是子进程修改的全局变量后父子进程读取到的 内容却不一样! ! ! ! 结论
变量内容不一样,所以父子进程输出的变量绝对不是同一个变量。但地址值是一样的说明该地址绝对不是物理地址在Linux地址下这种地址叫做虚拟地址。我们在用C/C语言所看到的地址全部都是虚拟地址物理地址用户一概看不到由OS统一管理。
OS必须负责将虚拟地址转化成物理地址
三让每一个进程都认为自己是独占系统中的所有资源
进程地址空间每一个进程在启动的时候都会让操作系统给他创建一个地址空间该地址空间就是进程地址空间
每一个进程都会有一个自已的进程地址空间! 操作系统要不要管理这些进程地址空间呢?? 先描述在组织 进程地址空间其实是内核的一个数据结构struct mm_ struct (稍后看! ) 举例子理解
我们往银行存10亿但是银行可能没10亿但银行给你画的饼就是10个亿。一个富豪有3个私生子富豪给每个私生子画的大饼说自己有10个亿以后都是你的财产大富豪: OS 三个私生子:进程 富翁给三个私生子画的大饼:进程地址空间 我不给你但是我这么说让你感觉我给你 让每一个进程都认为自己是独占系统中的所有资源的! !
四虚拟地址空间进程地址空间struct mm_ struct
1.概念
所谓的进程/虚拟地址空间:其实就是OS通过软件的方式给进程提供一个软件视角认为自己会独占系统的所有资源(内存)。 每个进程会维护一个mm_struct虚拟地址和物理内存通过页表建立映射关系。上学时一个班级中老师点名需要一张名单这个名单就是虚拟地址空间 定义就是从进程的视角看到的地址空间是进程运行时所用到的虚拟地址的集合地址最大的作用是唯一性。 我们在语言层面遇到的地址都是虚拟地址每个进程都有一个地址空间都认为自己独占物理内存。 linux下逻辑地址虚拟地址线性地址。
2.为什么不让PCB直接去访问物理地址
task_struct如果可以直接访问物理地址但是物理地址有很多进程如果你不小心寻址错误访问到了其他进程而这个进程是转账类似的那是不是很危险而如果我们有一层中间层不允许你直接访问物理地址而是在这之间对你的请求进行检查如果合法给你映射过去不合法就中止你的请求。例子就像const char* s“hello world”,*s‘H’这样是不允许的当页表识别出你是字符常量区的它映射时就不会给你w的权限本质上就是OS给你的权限只有r权限。每一个进程只隐射到合法内存不会恶意进程访问保护物理内存可以更方便进程与进程之间的解耦保证了独立性这样的特性。
4.为什么存在地址空间
保护内存。如果进程之间可以访问物理内存万一进程越界或者非法操作不安全进程管理-Linux内存管理。因为进程具有独立性一个进程对被共享的数据做修改如果影响了其他进程不能称之为独立性进程地址空间的存在可以更方便的进行进程和进程的数据代码之间的解耦保证了进程独立性这样的特征让进程或者程序以统一的视角来看待进程对应的代码和数据等各个区域方便使用编译器也已统一的角度来进行编译代码
4. 区域
每个区域范围都是可以有对应的编号的在虚拟地址空间 mm_struct 中有存储各个数据区的起始地址和结束地址也就是区域。
5.写时拷贝
写时拷贝正好可以回答fork 现象,子进程修改的全局变量后父子进程读取到的内容却不一样?
因为进程具有独立性一个进程对被共享的数据做修改如果影响了其他进程不能称之为独立性,任何一方尝试写入OS先进程数据拷贝更改页表映射然后让进程继续进行修改写时拷贝 操作系统自动做的(写时拷贝本身就是有OS的内存管理模块完成的!所以我们感知不到)。
写时拷贝g_val会再拷贝一份子进程中的映射关系会改变指向新的g_val但是g_val的虚拟地址相对地址还是原来的地址和父进程的g_val虚拟地址相对地址一样但是他们的物理地址不一样100改成200时只会改变新的g_val
6.为什么要写时拷贝?
为什么要写时拷贝创建子进程的时候就把数据分开不行吗?
父进程的数据子进程不一定全用即便使用也不一定全部写入——会有浪费空间的嫌疑最理想的情况只有会被父子修改的数据进行分离拷贝。不需要修改的共享即可——但是从技术角度实现复杂不可能实现如果fork的时候就无脑拷贝数据给子进程会增加fork的成本(内存和时间)
所以最终采用写时拷贝
写时拷贝只会拷父子修改的变相的就是拷贝数据的最小成本拷贝的成本依旧存在 **写时拷贝本质是延迟拷贝策略!**只有真正使用的时候才给你! 你想要但是不立马使用的空间先不给你那么也就意味着可以先给别人! 变相的提高内存的使用率!
7.fork有两个返回值pid_ t id ,同一个变量怎么会有不同的值? 当一个函数准备returnreturn 会被执行两次return 的本质就是通过寄存器将返回值写入到接受返回值的变量中其实在return之前你的子进程已经创建好了准备被调度了所以返回的本质就是写入谁先返回谁就先写入父进程和子进程各自执行return 当idfork()的时候谁先返回谁就要发生写时拷贝所以同一个变量会有不同的内容值本质是因为大家的虚拟地址是一样的但是大家对应的物理地址是不一样的! !