【Linux第五课-进程概念下】环境变量、程序地址空间
目录
- 环境变量
- main参数 --- 命令行参数
- 环境变量
- 环境变量特性 --- 命令行操作
- main函数的参数获取环境变量
- environ获取环境变量
- getenv()获取环境变量
- unset移除本地变量或环境变量
- set显示本地变量
- 代码获取和设置环境变量
- 本地变量
- 程序地址空间
- 什么是进程地址空间
- 为什么有地址空间+页表
- 内存申请
环境变量
是什么:环境变量是由系统提供的一组全局变量,每一个环境变量都有其不同的系统级用途。
为什么有:在不同的场景下,在执行某些任务或工作时,是需要知道更多的其他属性。eg:创建文件时,它就知道你是谁给你一定的权限。
每个用户都有属于自己的.bash_profle
main参数 — 命令行参数
main函数可以带参数:int argc 和 char * argv[]
char*数组argv指向一个一个的字符串
argc是指针数组里面元素个数
#include<stdio.h>int main(int argc, char* argv[])
{for(int i = 0; i < argc; i++){printf("argv[%d]: %s\n", i, argv[i]);}return 0;
}

argv必须以NULL结尾
为何这么做?
可以通过不同的选项,对于同一个程序可以使用内部不同的子功能
就像 ls -l
ls -a
ls -n
使用参数写一个计算器
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//./myprocess -[add|sub|mul|div]
int main(int argc, char* argv[])
{if(argc != 4){printf("./myprocess -{add|sub|mul|div} x y\n");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("%d / %d = %d\n", x, y, x/y);}return 0;
}

命令行参数是选项指令的基础
环境变量
不是一个,而是一堆,彼此之间没有关系
是系统内置的,具有特殊用途的变量
定义变量的本质,其实是开辟空间
操作系统/bash是C语言写的程序,他也能在运行中开辟空间
系统的环境变量,本质就是系统自己开辟的空间,给他名字和内容即可
执行pwd命令实际上是读取环境变量PWD
想要自己写写的程序和操作系统自带的命令一样直接使用,而不是./myprocess
需要将myprocess所在的路径加入到PATH 环境变量里面

环境变量特性 — 命令行操作
1、export
导入某个环境变量,env里面就有了

2、env

3、echo
main函数的参数获取环境变量
main函数除了有argc和argv两个参数以外,还有一个参数env
env是一个char*的数组用来存放父进程给的环境变量

上面就是自己打印的环境变量
int main(int argc, char* argv[], char* env[])
{printf("-----------\n");for(int i = 0; env[i];i++){printf("%s\n",env[i]);}return 0;
}
环境变量具有全局属性:环境变量会被所有的子进程即孙子进程继承,因此改变子进程的并不影响
environ获取环境变量
environ是一个二级指针

第一次用需要声明


getenv()获取环境变量
上面获取环境变量的方式太笼统,可以使用getenv()
环境变量可以使用USER限制谁可以访问该程序
头文件:
#include<stdlib.h>
int main(int argc, char* argv[], char* env[])
{const char* username=getenv("USER");if(strcmp("hui", username)==0){printf("this is my process\n");}else{printf("你没有权限\n");}return 0;
}
unset移除本地变量或环境变量
unset 变量名

set显示本地变量
环境变量是bash从磁盘里面读来的
代码获取和设置环境变量
想设置自己的环境变量在启动中就有,可以配置家目录下的.bash_profile


关掉重启,环境变量里面就有MYVAL

本地变量
本地变量不在环境变量中,可以set将shell里面的全部变量显示出来(环境变量和本地变量)


本地变量只能在bash内部有效,不能被子进程继承下去

myenv是导进去的环境变量可以被子进程继承,而hello是本地变量不是环境变量不能被子进程继承

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>int main()
{const char* myenv = getenv("myenv");if(myenv == NULL) printf("getenv() get null\n");else printf("myenv: %s\n", myenv);return 0;
}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>int main()
{//const char* myenv = getenv("myenv");if(myenv == NULL) printf("getenv() get null\n");else printf("myenv: %s\n", myenv);return 0;
}
程序地址空间
对于地址空间用代码的初步感受


堆栈相对而生

命令行参数和环境变量的严重,现有命令行参数表,再有环境变量这张表
argv+i:打印的是命令行参数那张表
argv[i]:环境变量字符串的地址
无论是表还是表指向的项目,都在栈上部
未初始化数据和以已初始化数据是全局变量
static变量是全局变量
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int g_unval;
int g_val = 100;int main(int argc, char* argv[], char* env[])
{printf("code addr:%p\n", main);printf("init data addr:%p\n", &g_val);printf("uninit data addr:%p\n", &g_unval);char* heap = (char*)malloc(20);char* heap1 = (char*)malloc(20);char* heap2 = (char*)malloc(20);char* heap3 = (char*)malloc(20);printf("heap addr:%p\n", heap);printf("heap1 addr:%p\n", heap1);printf("heap2 addr:%p\n", heap2);printf("heap3 addr:%p\n", heap3);static int i = 99;printf("static data addr:%p\n",&i);printf("stack addr:%p\n", &heap);printf("stack1 addr:%p\n", &heap1);printf("stack2 addr:%p\n", &heap2);printf("stack3 addr:%p\n", &heap3);for(int i = 0; argv[i]; i++){printf("argv[%d]:%p\n", i, argv[i]);//printf("&argv[%d]:%p\n", i, argv+i);}for(int i = 0; env[i]; i++){printf("env[%d]:%p\n", i, env[i]);//printf("&env[%d]:%p\n", i, env+i);}return 0;
}
问题?
上面那张图是内存吗?不是,叫作进程地址空间
验证
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int g_unval;
int g_val = 100;int main()
{pid_t id = fork();if(id == 0){//子进程int cnt = 0;while(1){printf("child, pid:%d, ppid:%d, g_val:%d, &g_val:%p\n",getpid(), getppid(), g_val, &g_val);cnt++;if(cnt == 5){printf("child: g_val 100->200\n");g_val = 200;}sleep(1);}}else{//父进程while(1){printf("father, pid:%d, ppid:%d, g_val:%d, &g_val:%p\n",getpid(), getppid(), g_val, &g_val);sleep(2);}}return 0;
}

这个地址绝对不是物理空间,这个地址叫作:虚拟地址/线性地址
语言中我们写代码所用到的所有地址都不是物理地址!
打出来的值不一样是因为,子进程的映射表已经改变,映射到不一样的物理地址
什么是进程地址空间
每一个进程,都存在一个进程地址空间,32[0, 4GB]
地址空间是一个内核数据结构,里面有各种类型的区域划分



地址空间,不具备对代码和数据的保存能力,在物理空间上存放
将地址空间上的地址(虚拟地址/线性)转换到物理空间中
给我们的进程提供一张映射表 — 页表
为什么有地址空间+页表
1、将物理内存从无序变成有序,让进程以统一的视角,看待内存
2、将进程管理和内存管理进程解耦合
3、当访问内存的时候,如果请求合法就会映射,请求不合法就不会映射,这就是地址空间和页表的作用
进程=内核数据结构+自己的代码和数据
内存申请
操作系统一定要为效率和资源使用率负责
1、申请的内存,你会直接使用吗? 不一定
2、申请内存,本质是在哪里申请? 本质申请是在进程地址空间中申请
new或malloc申请地址空间的时候,只是在虚拟地址上申请的,并没有在内存空间上申请。当第一次使用申请的空间的时候,会去访问页表,但页表里面找不到发生缺页中断,再去物理内存上申请。
优点
充分保证内存的使用率,不会空转
提升new或malloc的速度
相关文章:
【Linux第五课-进程概念下】环境变量、程序地址空间
目录 环境变量main参数 --- 命令行参数环境变量环境变量特性 --- 命令行操作main函数的参数获取环境变量environ获取环境变量getenv()获取环境变量unset移除本地变量或环境变量set显示本地变量 代码获取和设置环境变量 本地变量 程序地址空间什么是进程地址空间为什么有地址空间…...
mysql学习教程,从入门到精通,SQL 临时表(37)
1、SQL 临时表 在SQL中,临时表(Temporary Table)是一种在会话或连接期间临时存储数据的表。它们对于存储中间结果、简化复杂查询以及提高性能非常有用。以下是一个创建和使用临时表的示例。 假设我们有一个名为 employees 的表,…...
算法闭关修炼百题计划(四)
仅供个人复习 1.两数相加2.寻找峰值6.岛屿的最大面积3.最大数4.会议室5.最长连续序列6.寻找两个正序数组的中位数 1.两数相加 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请…...
头歌实践教学平台 大数据编程 实训答案(二)
第三阶段 Spark算子综合案例 Spark算子综合案例 - JAVA篇 第1关:WordCount - 词频统计 任务描述 本关任务:使用 Spark Core 知识编写一个词频统计程序。 相关知识 略 编程要求 请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下: …...
路由交换实验指南
案例 01:部署使用 eNSP 平台实验需求: 安装华为 eNSP 网络模拟平台打开 eNSP 平台,新建拓扑并绘制网络能够成功启动交换机、计算机设备 实验步骤: 安装华为 eNSP 网络模拟平台启动安装程序 配置安装内容 防护墙允许 eNSP 程序的…...
了解网页 blob 链接
blob 链接 自从 HTML5 提供了 video 标签,在网页中播放视频变得非常简单,只要在代码中插入一个 video 标签,再将 video 标签的 src 属性设置为视频的链接就可以了。由于 src 指向的是视频文件真实的地址,所以当我们通过浏览器的调…...
OpenGL笔记之事件驱动设计将相机控制类和应用程序类分离
OpenGL笔记之事件驱动设计将相机控制类和应用程序类分离 —— 2024-10-02 下午 bilibili赵新政老师的教程看后笔记 code review! 文章目录 OpenGL笔记之事件驱动设计将相机控制类和应用程序类分离1.代码图片2.分析3.UML4.代码 1.代码图片 运行 Mouse button 1 pressed at (1…...
低代码时代的企业信息化:规范与标准化的重要性
在当今数字化转型的浪潮中,企业的信息化建设正逐步向低代码平台倾斜。低代码不仅仅是简化开发过程,更是对企业内部流程、规范和标准化的深刻理解与应用。本文将探讨低代码在企业信息化中的重要性,特别是在运维和开发流程中的标准化࿰…...
理解无监督学习、无监督图像分割
系列文章目录 文章目录 系列文章目录一、无监督学习如何学习 能不能举一个非常具体的例子,带着运算过程的例子总结 二、在图像分割中呢,具体怎样实现无监督示例:使用自编码器和k-means进行无监督图像分割1. **数据准备**2. **构建自编码器**3…...
C语言— exec系列函数
exec系列函数 在C语言编程中,exec 系列函数用于在当前进程中执行一个新程序,从而替换当前进程的映像。这些函数不会返回,除非发生错误。exec 系列函数有多个变体,其中最常用的包括 execl, execle, execlp, execv, execve, execvp…...
命名管道Linux
管道是 毫不相关的进程进程间通信::命名管道 管道 首先自己要用用户层缓冲区,还得把用户层缓冲区拷贝到管道里,(从键盘里输入数据到用户层缓冲区里面),然后用户层缓冲区通过系统调用(write)写…...
【ios】---swift开发从入门到放弃
swift开发从入门到放弃 环境swift入门变量与常量类型安全和类型推断print函数字符串整数双精度布尔运算符数组集合set字典区间元祖可选类型循环语句条件语句switch语句函数枚举类型闭包数组方法结构体 环境 1.在App Store下载Xcode 2.新建项目(可以先使用这个&…...
【AUTOSAR 基础软件】PduR模块详解(通信路由)
文章包含了AUTOSAR基础软件(BSW)中PduR模块相关的内容详解。本文从AUTOSAR规范解析,ISOLAR-AB配置以及模块相关代码分析三个维度来帮读者清晰的认识和了解PduR这一基础软件模块。文中涉及的ISOLAR-AB配置以及模块相关代码都是依托于ETAS提供的…...
[控制理论]—差分变换法与双线性变换法的基本原理和代码实现
差分变换法与双线性变换法的基本原理和代码实现 1.差分变换法 差分变换法就是把微分方程中的导数用有限差分来近似等效,得到一个与原微分方程逼近的差分方程。 差分变换法包括后向差分与前向差分。 1.1 后向差分法 差分变换如下: d e ( t ) d t e…...
【JavaEE】——多线程常用类
阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 引入: 一:Callable和FutureTask类 1:对比Runnable 2:…...
Cilium-实战系列-(二)Cilium-Multi Networking-多网络
一、Cilium必要开启的功能 1、enable-multi-network 2、ipam模式选择:multi-pool 二、涉及的CRD资源 1、 ciliumpodippools.cilium.io *通过Cilium管理节点上的pod cidr.网络分为主网络和第二网络。 *主网络的 ciliumpodippools.cilium.io default根据配置文件默认生成的。 …...
springboot自动配置
自动配置的核心就在SpringBootApplication注解上,SpringBootApplication这个注解 底层包含了3个注解,分别是: SpringBootConfiguration ComponentScan EnableAutoConfiguration EnableAutoConfiguration这个注解才是自动配置的核心,它 封…...
mock数据,不使用springboot的单元测试
业务代码 package com.haier.configure.service.impl;import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.haier.common.util.RequestUtil; import com.haier.configure.entity.Langua…...
【pytorch】pytorch入门5:最大池化层(Pooling layers )
文章目录 前言一、定义概念 缩写二、参数三、最大池化操作四、使用步骤总结参考文献 前言 使用 B站小土堆课程 一、定义概念 缩写 池化(Pooling)是深度学习中常用的一种操作,用于降低卷积神经网络(CNN)或循环神经网…...
职场上的人情世故,你知多少?这五点一定要了解
职场是一个由人组成的复杂社交网络,人情世故在其中起着至关重要的作用。良好的人际关系可以帮助我们更好地融入团队,提升工作效率,甚至影响职业发展。在职场中,我们需要了解一些关键要素,以更好地处理人际关系…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...



