当前位置:首页 » 《资源分享》 » 正文

【Linux】借命令行参数的引导,探索环境变量的奥秘

12 人参与  2024年09月20日 12:00  分类 : 《资源分享》  评论

点击全文阅读


目录

1.命令行参数

1.1.概念:

1.2.利用命令行参数打造计算器:

2.环境变量

2.1.环境变量是什么?

2.2.有什么方法可以不用带路径,直接就可以运行自己的程序呢?

法一:

法二:

2.3.通过代码如何获取环境变量

main()函数第三个参数

通过第三方变量environ获取

3.进程地址空间:

3.1奇怪的现象:

3.2.用进程空间解释该现象

3.3.地址空间的原理

3.4.为什么要有地址空间+页表?

3.5.问题:malloc/new申请内存相关问题:

1.命令行参数

1.1.概念:

命令行参数是指在执行一个程序或命令时,通过命令行输入的附加信息和选项。

我们为什么会有不同的指令对应的不同的功能,就是因为命令行参数的存在,命令行参数就是Linux指令选项的基础!

注意我们的main()函数也是有参数的,且有三个参数,也就是命令行参数。

我们首先来研究main函数的前两个参数:一个整数类型的参数argc和一个字符指针数组类型的参数argv。其中,argc表示命令行参数的个数,同时也表示argv数组中元素的个数,而argv是一个指向参数值的指针数组,每个指针指向一个命令行参数的字符串

注意在argv数组存储的时候,默认第一个参数就是程序的名称。最后一个参数是NULL

字符串会被bash解析成一对多,放在指针数组里面,这些都是操作系统自己完成的!

如何获取环境?利用命令行传参,main函数第二个参数,会把所有环境参数都会被解析成一对多进行输出

所以我们可以通过不同的选项,让我们的同一个程序执行它内部不同的功能

1.2.利用命令行参数打造计算器:

int main(int argc, char* argv[], char* env[]){    // ./myprocess -add 1 2 有4个参数,所以argc == 4    if (argc != 4)    {        printf("Usage:\n\t%s -[add|sub|mul|div] x y\n\n", argv[0]);        return 1;    }    int x = atoi(argv[2]);    int y = atoi(argv[3]);    if (strcmp("-add", argv[1]) == 0)    {        printf("%d+%d=%d\n", x, y, x + y);    }    else if (strcmp("-sub", argv[1]) == 0)    {        printf("%d-%d=%d\n", x, y, x - y);    }    else if (strcmp("-mul", argv[1]) == 0)    {        printf("%d*%d=%d\n", x, y, x * y);    }    else    {        printf("unknown!\n");    }    return 0;}

2.环境变量

2.1.环境变量是什么?

是由系统提供的全局变量,每一个环境变量都有它的系统和用途

这个概念很明显有点抽象,接下来给大家举几个例子,就能理解了。

我们知道,当我们运行自己的程序是都需要加上 ./ 而我们用 ls mv等指令却不需要加上 ./ 这是为什么呢?

这就跟我们其中的一个环境变量有关了,名叫PATH。在运行程序,系统会去用PATH中存的默认路径,通过路径去查找我们要执行的程序。ls mv等系统指令都是默认存放在这些路径当中,但是你自己写的程序默认路径不在环境变量中的路径,找不到就需要说明在当前目录 ./就是表明在当前目录!

查看环境变量:使用指令   echo $[环境变量]

以:分隔,都是一个一个子路径

2.2.有什么方法可以不用带路径,直接就可以运行自己的程序呢?

法一:

直接将我们的程序拷贝到PATH默认路径下的任意一个。这一操作相当于将自己的软件安装到系统当中了。这种方法并不推荐,会污染环境!

法二:

我们可以将当前路径添加到环境变量PATH当中,当成系统的子路径,这样也可以不用./ 可以直接执行!

指令: PATH=$PATH:想要添加的路径

注意环境变量具有全局属性,全局变量会被所有的子进程包括孙子进程进行继承!

2.3.通过代码如何获取环境变量

main()函数第三个参数

#include <stdio.h>int main(int argc, char *argv[], char *env[]){int i = 0;for(; env[i]; i++){printf("%s\n", env[i]);}return 0;}

通过第三方变量environ获取

#include <stdio.h>int main(int argc, char *argv[]){extern char **environ;int i = 0;for(; environ[i]; i++){printf("%s\n", environ[i]);}return 0;}

3.进程地址空间:

每一个进程都有自己的地址空间

3.1奇怪的现象:

父进程和子进程的值不同,但是为什么父进程和子进程的地址是一样的!?

3.2.用进程空间解释该现象

上图我们用红色框住的地址,绝对不是物理地址!不然地址不可能会相同的,这个地址叫做虚拟地址(线性地址)!

我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理,下面这张图对应的都是虚拟地址,同样也是我们的地址空间!

父进程和子进程地址都不变,但是经过页表映射关系访问了不同的内存,所以打印出来的值是不一样的

上面的图就足以说明问题:

同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址!

3.3.地址空间的原理

地址空间相当于就是操作系统给每一个进程画的大饼,所以并不会直接在物理内存中开辟空间,而是会用虚拟地址,当这个进程真正需要利用内存的时候,才会通过页表将虚拟内存映射到物理内存当中。

那么操作系统要不要对地址空间进行管理?当然是需要的,我们要先描述,再组织,进程地址空间是数据结构,具体到进程中,就是特定数据结构的对象!

区域划分的本质就是区域内的各个地址都可以使用,进行充分利用!

进程的地址空间一定有整数描述的各个区域,跟三八线用整数描述是一个道理。

在虚拟地址申请的内存空间不会立刻给你在屋里内存中申请,而是会等待你真正需要内存空间的时候才会在物理空间中开辟,地址空间相当于是一个支票,等到你需要的时候才会给你真正的申请空间

3.4.为什么要有地址空间+页表?

将物理内存从无序变有序,让进程以统一的视角,看待内存将进程管理和内存管理进行解耦合地址空间+页表是保护内存安全的重要手段

我们的地址空间,不具备对我们的代码和数据的保存能力!是在物理内存中存放的。

页表的最大作用就是将地址空间上的地址(虚拟/线性)转化到物理内存当中!

我们当用malloc申请空间时,我们其实并没有在地址空间中申请,而是在地址空间上开辟空间,我们经过页表+物理内存映射,但是我们当前并没有建立映射关系,就会出现缺页中断!

缺页中断会暂停程序执行,将控制权交给操作系统内核。 内核会检查缺失的页面是否在磁盘上,并进行必要的页面置换。

3.5.问题:malloc/new申请内存相关问题:

1、申请的内存,你会直接使用吗

不一定

2、申请内存,本质是在哪里申请?

在进程的虚拟空间中申请。

注意操作系统一定要为效率和资源使用率负责,保证内存的使用率,不会空转,提升new或者malloc的速度


点击全文阅读


本文链接:http://zhangshiyu.com/post/162140.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1