[Linux 进程(四)] 再谈环境变量,程序地址空间初识

在这里插入图片描述

文章目录

  • 1、前言
  • 2、环境变量
    • 2.1 main函数第三个参数 -- 环境参数表
    • 2.2 本地环境变量和env中的环境变量
    • 2.3 配置文件与环境变量的全局性
    • 2.4 内建命令与常规命令
    • 2.5 环境变量相关的命令
  • 3、程序地址空间

1、前言

上一篇我们讲了环境变量,如果有不明白的先读一下上一篇文章:环境变量讲解
本篇文章我们继续完善环境变量这章剩下的内容,以及main函数第三个参数的详解,进程地址空间的初始。

2、环境变量

2.1 main函数第三个参数 – 环境参数表

看完上一篇文章的同学,肯定知道了如何查看环境变量,命令行输入 env:
我们查看一下:
在这里插入图片描述

我们main函数的参数列表中,第三个就是环境变量表,没错它里面就记录着这些环境变量。
它与第二个参数一样,都是char类型的指针数组。我们写一段代码,打印一下环境变量表中的内容:

#include <stdio.h>

int main(int argc, char* argv[], char* env[])
{
	int i = 0;
    for( ; env[i]; i++)
    {
        printf("env[i]: %s\n", i, env[i]);
    }
    
    return 0;
}

在这里插入图片描述

我们发现main函数的第三个参数,环境参数表跟我们env所查出来的内容是一模一样的。
这是因为我们程序在运行时,环境变量是系统给传的。
问题:
那这个给程序传环境变量的系统是谁?
在学习fork的时候,我们知道fork()函数是可以创建子进程的。同时我们也知道命令行启动的进程都是shell/bash的子进程,子进程的命令行参数和环境变量,是父进程bash给传递的!
问题:
那父进程bash的环境变量信息又是从哪里来的?
我们在上一篇中讲到,PATH内容修改后,下一次启动Xshell时,PATH内容又自动恢复了。这其实是我们直接更改了bash进程内部的环境变量信息!
每一次重新登录,都会给我们形成新的bash解释器并且新的bash解释器自动从 哪里 读取自己的环境变量表信息!
虽然我们现在还不知道父进程环境变量哪里来的,但是环境变量存在哪我就直接说了:环境变量信息是以脚本配置文件的形式存在的!
在登录目录下有一个.bash_profile脚本文件,每一次登录的时候,bash进程都会读取 .bash_profile配置文件中的内容,为我们bash形成一张环境变量表信息!
在这里插入图片描述

2.2 本地环境变量和env中的环境变量

我们可以在bash中直接定义环境变量:环境变量名 = 内容
我们来试一下:
在这里插入图片描述

用户定义的环境变量是本地的,env是查看不了本地环境变量的。
在这里插入图片描述

如果我们想要把我们自己定义的环境变量,导出到env所能查看到的环境变量中,我们可以使用以下命令:

export 环境变量名

在这里插入图片描述

还可以直接使用export定义环境变量:
在这里插入图片描述

当我们把自己定义的环境变量放入了bash的环境变量后,我们在main函数所打印的环境变量中能不能找到呢,我们试一下:
在这里插入图片描述

我们在命令行中输入的命令都是bash的子进程,这就验证了子进程的环境变量是由父进程给传递的。

2.3 配置文件与环境变量的全局性

问题:
我们要是重新登录Xshell的话,我们刚导出的环境变量还在吗?
在不在我们测试一下就出来了:
在这里插入图片描述

明显是不在的,我们刚才导出是直接给bash进程的内部导出了。我们重新启动后 .bash_profile脚本文件会重新执行,bash进程内部的环境变量会重新读取并形成一份新的环境变量表。
如果我们想要每次登录后,bash的环境变量表都有我们自己添加的环境变量,我们就需要在 .bash_profile脚本文件中添加,此后再登录后bash的环境变量表中就有了添加的环境变量。

在这里插入图片描述
在这里插入图片描述
我们再介绍一个获取环境变量的系统调用函数,const char ** environ
在这里插入图片描述
我们发现environ的类型是一个二级指针,这里不卖关子了,它其实指的是环境变量表首元素:
在这里插入图片描述
我们写一段代码将其内容打印出来:

#include <stdio.h>
#include <unistd.h>

int main()
{
	extern char** environ;
    int i = 0;
    for(i = 0; environ[i]; i++)
    {
        printf("environ[%d]: %s\n", i, environ[i]);
    }
    
	return 0;
}

在这里插入图片描述

问题: 大家有没有想过,如果我们本地环境变量,子进程会将我们添加的本地环境变量也继承下来吗?
我们做一下实验:
在这里插入图片描述
显然是没有的(这里细心的人会发现echo为什么就继承下来了,其实echo不是子进程,别急下一个话题我们就会讲到)。如果我们将本地变量导出到系统环境变量中,子进程就会将其继承下来。
总结:
1、迄今为止我们学到了三种获取环境变量的方式:

  • getenv();
  • main函数传参方式;
  • extern char** environ;

2、bash再去创建子进程时,bash会给子进程传递一份同样的环境变量,子进程再创建子进程天然的就继承了父进程的环境变量表,也就间接获取了bash所传递的环境变量所以系统环境变量具有全局属性!

3、本地环境变量 vs 系统环境变量

  • 本地环境变量只在bash进程内部有效,不会被子进程继承下去;
  • 系统环境变量通过让所有子进程继承的方式,实现自身的全局性!

2.4 内建命令与常规命令

通过上一篇的学习,我们知道了,bash自己的指令可以直接使用,不用加 ./,因为这些指令在系统默认路径PATH下,现在我们将PATH置空,这些指令就运行不了了!
在这里插入图片描述

我们发现,有些指令确实不能运行了,但是有些指令仍然可以运行。这是为什么呢?
Linux下命令分为两类:

  • 常规命令:shell通过fork创建子进程,让子进程执行的;
  • 内建命令:shell命令行的一个函数。

原来pwd,echo都是内建命令。
那为什么内建命令就直接能读取环境变量呢?
内建命令是shell内部的一个函数,父进程内部执行,它是可以直接看到父进程内部的,当然可以直接读取shell内部定义的本地变量!

2.5 环境变量相关的命令

  1. echo: 显示某个环境变量值
  2. export: 导出一个新的环境变量
  3. env: 显示所有环境变量
  4. unset: 清除环境变量
  5. set: 显示本地定义的shell变量和环境变量
    在这里插入图片描述

3、程序地址空间

C/C++程序员认为,程序内存分布是这样子的:
在这里插入图片描述
我们写一段代码验证一下:

#include <stdio.h>
#include <stdlib.h>

int uninit_global;
int init_global = 0;
int main(int argc, char* argv[], char* env[])
{
    printf("code address: %p\n", main); // 代码区
    const char* str = "Hello Linux!\n";
    printf("read only char address: %p\n", str); // 字符常量区
    printf("init global value address: %p\n", &init_global);
    printf("uninit global value address: %p\n", &uninit_global);

    char* heap1 = (char*)malloc(sizeof(char)*100);
    char* heap2 = (char*)malloc(sizeof(char)*100);
    char* heap3 = (char*)malloc(sizeof(char)*100);
    char* heap4 = (char*)malloc(sizeof(char)*100);
    static int a = 0;
    printf("heap1 address: %p\n", heap1);                                                                                         
    printf("heap2 address: %p\n", heap2);
    printf("heap3 address: %p\n", heap3);
    printf("heap4 address: %p\n", heap4);

    printf("stack address: %p\n", &str);
    printf("stack address: %p\n", &heap1);
    printf("stack address: %p\n", &heap2);
    printf("stack address: %p\n", &heap3);
    printf("stack address: %p\n", &heap4);
	printf("a address: %p\n," &a);

    int i = 0;
    for(i = 0; i < argc; i++)
    {
        printf("argv[%d]: %p\n", i, argv[i]);
    }

    for(i = 0; env[i]; i++)
    {
        printf("env[%d]: %p\n", i, env[i]);
    }
    return 0;
}

在这里插入图片描述

我们在这里就能看出来:
1、堆上的地址内存的使用是不断增大;
2、栈上的地址内存的使用是不断减小的但是在我们c/c++中,定义数组、结构体或者整型,它们的地址是向上增长的。比如,开辟一个十个元素的整型数组,一次整体开出来,首元素地址在最低,因此遍历时是++操作。
3、static修饰的静态成员变量,其实就是全局变量,他就放在已初始化全局变量区,所以它在全局就一份。
4、栈区之上先是命令行参数,再是环境变量,不断向上增上的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/329267.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

黑马程序员——html css基础——day01——HTML基础

目录&#xff1a; 今日课程介绍 核心技术点标签语法HTML骨架标签的关系注释标题标签段落标签换行和水平线文本格式化标签图像标签 图像属性属性语法路径 相对路径绝对路径超链接标签音频视频综合案例一个人简介综合案例二Vue简介 1.今日课程介绍 今日目标&#xff1a;掌握标…

连接超时的问题

连接超时的问题 通用第三方工具连接超时 connect timeout 方案一&#xff1a; /etc/ssh/sshd_config node1上操作&#xff0c;图是错的 方案二&#xff1a; windows上Hosts文件域名解析有问题 比如&#xff1a; 192.168.xx.100 node1 192.168.xx.161 node1 两个都解析成node…

Peter算法小课堂—并查集

我们先来看太戈编程467题 攀亲戚 题目描述&#xff1a; 最近你发现自己和古代一个皇帝长得很像&#xff1a;都有两个鼻子一个眼睛&#xff0c;你想知道这皇帝是不是你的远方亲戚&#xff0c;你是不是皇亲国戚。目前你能掌握的信息有m条&#xff0c;关于n个人&#xff1a;第i条…

论文翻译: Vision-Language Foundation Models as Effective Robot Imitators

Vision-Language Foundation Models as Effective Robot Imitators 使用视觉-语言基础模型对机器人进行有效的模仿 文章目录 Vision-Language Foundation Models as Effective Robot Imitators使用视觉-语言基础模型对机器人进行有效的模仿ABSTRACT摘要1 INTRODUCTION1 引言2 …

huggingface学习 | 云服务器使用git-lfs下载huggingface上的模型文件

文章目录 一、找到需要下载的huggingface文件二、准备工作&#xff08;一&#xff09;安装git-lfs&#xff08;二&#xff09; 配置git ssh 三、检查ssh连接huggingface是否成功 一、找到需要下载的huggingface文件 huggingface官网链接&#xff1a;https://huggingface.co/ 以…

东北编程语言???

在GitHub闲逛&#xff0c;偶然发现了东北编程语言&#xff1a; 东北编程语言是由Zhanyong Wan创造的&#xff0c;它使用东北方言词汇作为基本关键字。这种编程语言的特点是简单易懂&#xff0c;适合小学文化程度的人学习&#xff0c;并且易于阅读、编写和记忆。它的语法与其他编…

Linux下安装Mysql【CentOS7 】

Linux下安装Mysql 一、Linux下安装Mysql-5.7.41【tar包下载安装】1.1.首先检查是否已经安装过mysql1.2.下载Linux版本的Mysql-5.71.3.解压缩1.4.安装执行 rpm 安装包需要先下载 openssl-devel 插件1.5.安装 Mysql5.7 执行 rpm 安装包1.6.Mysql相关操作命令1.7.查看Mysql-5.7 临…

生物制药行业研究:预计2029年将达到559亿美元

生物制药是指运用微生物学、生物学、医学、生物化学等的研究成果&#xff0c;从生物体、生物组织、细胞、器官、体液等。综合利用微生物学、化学、生物化学、生物技术、药学等科学的原理和方法制造的一类用于预防、治疗和诊断的制品。 生物制药上游行业主要涉及酵母粉、葡萄糖…

【JavaEEj进阶】 Spring实现留言板

文章目录 &#x1f38d;预期结果&#x1f340;前端代码&#x1f384;约定前后端交互接⼝&#x1f6a9;需求分析&#x1f6a9;接⼝定义 &#x1f333;实现服务器端代码&#x1f6a9;lombok &#x1f332;服务器代码实现&#x1f334;运⾏测试 &#x1f38d;预期结果 可以发布并…

Qt 调试系统输出报警声以及添加资源

文章目录 前言一、方法1 使用 Qsound1.添加都文件 直接报错2.解决这个错误 添加 QT multimedia3. 加入代码又遇到新的错误小结 二、第二种方法1.引入库2.添加资源2.1依次点击Qt--->Qt Resource File--->Choose2.2给资源文件起个名字&#xff0c;如&#xff1a;res&#…

【管理篇 / 升级】❀ 13. FortiOS 7.4固件升级新规则 ❀ FortiGate 防火墙

【简介】飞塔防火墙的固件升级一直是所有厂家中最好的。只要有注册官方帐号&#xff0c;有注册设备&#xff0c;并且只要有一台设备在服务期内&#xff0c;即可下载所有型号的所有版本的固件。即使其它设备服务期已过&#xff0c;也可以通过固件文件手动升级&#xff0c;避免防…

QT界面表格加入勾选框和表格更改颜色显示NG和OK

在QTableWidget上添加框选&#xff0c;获取框选状态 添加选项框在表格中 //添加选择框QTableWidgetItem* check0 new QTableWidgetItem();check0->setCheckState(Qt::Checked);ui->tableWidget_TestResult->setItem(0, 0, check0);ui->tableWidget_TestResult->…

linux安装QQ(官方正版)

QQ官网上有支持linux系统的版本&#xff0c;所以去官网直接下载正版就好。 安装步骤&#xff1a; 1.进入官网&#xff1a;https://im.qq.com/linuxqq/index.shtml 2.选择版本&#xff1a;X86版下载dep 如下所示&#xff1a; 3.下载qq安装包&#xff1a; 4.使用命令安装qq s…

读人工智能专业可以考什么证书呢?

由国家工信部权威认证的人工智能证书是跨入人工智能行业的敲门砖&#xff0c;随着人工智能技术的发展越来越成熟&#xff0c;相关的从业人员也会剧增&#xff0c;证书的考取难度也会变高。如果已经从事或者准备从事人工智能行业的人员&#xff0c;对于考证宜早不宜迟&#xff0…

自建服务器如何备案?

随着互联网的普及和发展&#xff0c;越来越多的人开始考虑自建服务器。然而&#xff0c;在中国大陆地区&#xff0c;自建服务器需要进行备案。本文将介绍自建服务器备案的流程、所需材料以及注意事项。 一、备案流程 确定备案地区 根据《中华人民共和国计算机信息网络国际联网…

excel(vab)删除空行

删除第一、二、三列位空的所有行&#xff08;8000)行范围以内 代码如下&#xff1a; Sub Macro1()Dim hang As Integer For hang 8000 To 1 Step -1If Sheet1.Cells(hang, 1) "" And Sheet1.Cells(hang, 2) "" And Sheet1.Cells(hang, 3) "&quo…

软件测试|Docker cp命令详解:在Docker容器和主机之间复制文件/文件夹

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

安泰功率信号源设计方法有哪些

在电子系统中&#xff0c;功率信号源是一个关键的组成部分&#xff0c;用于提供稳定、可靠的电能。这篇文章将详细介绍功率信号源的设计方法&#xff0c;包括选择功率源类型、设计电源拓扑结构、提高效率和管理电磁干扰等方面。 1.功率源类型的选择 选择适当的功率源类型是功率…

MySQL下对[库]的操作

目录 创建数据库 创建一个数据库案例&#xff1a; 字符集和校验规则&#xff1a; 默认字符集&#xff1a; 默认校验规则&#xff1a; 查看数据库支持的字符集&#xff1a; 查看数据库支持的字符集校验规则&#xff1a; 校验规则对数据库的影响&#xff1a; 操作数据…

【计算机硬件】3、输入输出技术、总线结构

文章目录 输入输出技术内存与接口地址的编址方法1、 内存与接口地址独立编址方法2、内存与接口地址统一编址方法 计算机和外设间的数据交互方式1、程序控制(查询)方式2、程序中断方式3、DMA方式&#xff08;直接主存存取&#xff09; 总线结构 输入输出技术 内存与接口地址的编…