【Linux第五课-进程概念下】环境变量、程序地址空间

news2024/10/6 7:33:59

目录

  • 环境变量
      • 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的速度

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

预算有限也能玩转 AI:香橙派、树莓派与 Jetson 的选择攻略

随着 AI 技术的迅猛发展&#xff0c;越来越多的边缘计算设备可以处理从轻量级任务到复杂的 AI 模型。在本文中&#xff0c;我们将对比几款主流的边缘 AI 设备&#xff0c;包括 NVIDIA Jetson 系列、香橙派 和 树莓派 5&#xff0c;并探讨 Hailo 加速器 在边缘 AI 领域的潜力。我…

【学习笔记】手写一个简单的 Spring MVC

目录 一、什么是Spring MVC &#xff1f; Spring 和 Spring MVC 的区别&#xff1f; Spring MVC 的运行流程&#xff1f; 二、实现步骤 1. DispatcherServlet 1. 创建一个中央分发器 拦截所有请求 测试 2. 接管 IOC 容器 1. 创建配置文件 2. 修改 web.xml 配置文件 …

vSAN03:vSAN故障处理、节点维护、删除节点、关闭/重启/删除vSAN集群

目录 vSAN故障处理单节点维护从vSAN集群中永久删除节点关闭vSAN集群重启vSAN集群删除vSAN集群 vSAN故障处理 级别状态处理可能原因活动正常无无缺失vSAN 检测到临时组件故障&#xff0c;且其中的组件可以恢复并还原其工作状态&#xff0c;则该组件将处于“缺失”状态。&#x…

分析JS Crash(进程崩溃)

一、JS Crash异常检测能力 1、JS Crash日志规格 以下是进程崩溃日志信息中对应字段解释。 Build info:XXX-XXXX X.X.X.XX(XXXXXXXX) <- 版本信息 Module name:com.example.myapplication <- 模块名 Version:1.0.0 <- 版本号 Pid:579 <- 进程号 Uid:0 <- 用户ID…

【Qt】Qt学习笔记(一):Qt界面初识

Qt 是一个跨平台应用程序和 UI 开发框架。使用 Qt 您只需一次性开发应用程序&#xff0c;无须重新编写源代码&#xff0c;便可跨不同桌面和嵌入式操作系统部署这些应用程序。Qt Creator是跨平台的Qt集成开发环境。 创建项目 Qt的一些界面&#xff0c;初学时一般选择Qt Widgets …

VirtualBox虚拟机连接宿主机并能够上网(小白向)

现存问题 windows系统主要使用vmare和virtualbox两种虚拟机&#xff0c;virtualbox相对于vmare更加轻便&#xff0c;但少有博客能够详细说明使用virtualbox的教程。踩了网上的坑后&#xff0c;决定写一篇文章介绍virtualbox虚拟机上网的流程。 需求 1. virtualbox虚拟机与宿主机…

Linux 文件 IO 管理(第四讲:软硬链接和动静态库)

Linux 文件 IO 管理&#xff08;第四讲&#xff1a;软硬链接和动静态库&#xff09; 软硬链接操作与现象软链接硬链接 解释软链接硬链接作用 动静态库初识静态库怎么做库&#xff08;开发角度&#xff09;怎么用库&#xff08;使用角度&#xff09;安装当前目录直接使用 动态库…

JavaWeb程序设计(第四版)习题参考答案

JavaWeb程序设计&#xff08;第四版&#xff09;习题参考答案 目录 模块1 习题参考答案 模块2 习题参考答案 模块3 习题参考答案 模块4 习题参考答案 模块5 习题参考答案 模块6 习题参考答案 模块7 习题参考答案 模块8 习题参考答案 模块1 习题参考答案 选择题 1 .A …

WaveletGPT:基于小波的多尺度表征增强大型语言模型训练效率

斯坦福大学的研究人员首次将小波理论应用于大型语言模型&#xff0c;提出了WaveletGPT&#xff0c;通过在Transformer解码器层中添加多尺度滤波器&#xff0c;加速了模型训练速度&#xff0c;并在文本、音频和音乐等多个领域取得了显著的性能提升。 论文介绍 大型语言模型 (L…

求和问题题解

减 sort拍后就A了 #include <bits/stdc.h> #include <cstring> using namespace std; typedef long long ll; ll n,a[400005],cnt0,b[400005]; bool cmp(long long x,long long y){return x>y; } int main () {cin>>n;for(int i1;i<n;i){cin>>…

查缺补漏----同步,异步,半同步,分离式通信

目录 1.同步通信&#xff08;同步定时方式&#xff09; 2.异步通信 3.半同步通信 4.分离式通信 1.同步通信&#xff08;同步定时方式&#xff09; 同步通信方式&#xff08;比如SPI&#xff09;&#xff0c;是把许多字符组成一个信息组&#xff0c;这样&#xff0c;字符可…

Springboot 整合 durid

文章目录 Springboot 整合 druiddruid的优势配置参数使用整合 Druid配置数据源配置参数绑定配置参数配置监控页面配置拦截器 Springboot 整合 druid druid的优势 可以很好的监控 DB 池连接 和 SQL 的执行情况可以给数据库密码加密可以很方便的编写JDBC插件 配置参数 使用 整…

数据结构之树(4)

摘要&#xff1a;本篇主要讲哈夫曼树、并查集、二叉排序树、平衡二叉树等&#xff0c;非常非常非常重要&#xff01;&#xff01;&#xff01; 一、哈夫曼树 基于霍夫曼树&#xff0c;利用霍夫曼编码进行通信可以大大提高信道利用率&#xff0c;缩短信息传输时间&#xff0c;…

Android2024.2.1升级错误

提示 Gradle 版本不兼容&#xff0c;升级后就报错了 。 1.gradle安装包镜像 distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists //distributionUrlhttps\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrlhttps://mirrors.cloud.tencen…

Koa2项目实战1(项目搭建)

前言 在正式开始之前&#xff0c;需要先知道用到的东西&#xff1a; koa&#xff1a;Koa 是一个基于 Node.js 的 Web 应用框架&#xff0c;非常适合开发API服务&#xff0c;可以与前端框架&#xff08;如 Vue.js、React.js&#xff09;结合使用&#xff0c;实现前后端分离的开…

第八篇:磁盘管理(1)

目录 6.1分区 6.1.1基本分区 6.1.1.1磁盘的相关知识 6.1.1.1.1基础知识 6.1.1.1.2命名 1.对于串口硬盘&#xff1a;/dev/sda、/dev/sdb、/dev/sdc......往后都是一个字母一个字母的累加 2.对于并口硬盘&#xff1a;/dev/hda其余相同 6.1.1.1.3磁盘的分区方式 方式1&am…

c++_ 多态

目录 一.多态 1.1多态(polymorphism)的概念 1.2实现多态还有两个必须重要条件&#xff1a; 1.3 重载 和 虚函数的重写/覆盖 和 隐藏 的比对 1.4 协变(了解) 1.5 析构函数的重写 1.6 override 和final关键字 二.纯虚函数和抽象类 三. 多态的原理 3.1虚函数表指针 3.…

黑马JavaWeb开发跟学(十一)SpringBootWeb案例

黑马JavaWeb开发跟学十一.SpringBootWeb案例 SpringBootWeb案例1. 新增员工1.1 需求1.2 接口文档1.3 思路分析1.4 功能开发1.5 功能测试1.6 前后端联调 2. 文件上传2.1 简介2.2 本地存储2.3 阿里云OSS2.3.1 准备2.3.2 入门2.3.3 集成 3. 修改员工3.1 查询回显3.1.1 接口文档3.1…

性能测试笔记2-总

安装路径&#xff1a;先装jdk,后装JMeter 安装JDK&#xff1a; 下载JDK – 安装JDK – 配置环境变量 – 验证 安装Jmeter&#xff1a; 下载Jmeter – 安装Jmeter – 配置环境变量 – 启动验证 注意点&#xff1a; 下载JDK时&#xff0c;注意电脑操作系统是32位/64位 下载…

力扣 简单 110.平衡二叉树

文章目录 题目介绍解法 题目介绍 解法 平衡二叉树:任意节点的左子树和右子树的高度之差的绝对值不超过 1 //利用递归方法自顶向下判断以每个节点为根节点的左右子树的最大深度是否大于1 class Solution {public boolean isBalanced(TreeNode root) {if(root null){return tr…