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

目录

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.利用命令行参数打造计算器:

cpp 复制代码
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()函数第三个参数

cpp 复制代码
#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获取

cpp 复制代码
#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的速度

相关推荐
cominglately2 小时前
centos单机部署seata
linux·运维·centos
魏 无羡2 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos
CircleMouse2 小时前
Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org
linux·运维·服务器·centos
木子Linux3 小时前
【Linux打怪升级记 | 问题01】安装Linux系统忘记设置时区怎么办?3个方法教你回到东八区
linux·运维·服务器·centos·云计算
mit6.8243 小时前
Ubuntu 系统下性能剖析工具: perf
linux·运维·ubuntu
鹏大师运维3 小时前
聊聊开源的虚拟化平台--PVE
linux·开源·虚拟化·虚拟机·pve·存储·nfs
watermelonoops3 小时前
Windows安装Ubuntu,Deepin三系统启动问题(XXX has invalid signature 您需要先加载内核)
linux·运维·ubuntu·deepin
滴水之功4 小时前
VMware OpenWrt怎么桥接模式联网
linux·openwrt
ldinvicible4 小时前
How to run Flutter on an Embedded Device
linux
YRr YRr5 小时前
解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误
linux·opencv·ubuntu