C语言中的虚拟地址

虚拟地址

虚拟地址空间

  • 对于操作系统而言,每个进程所得到的虚拟地址都在一个独立的固定的范围内,不会超过这个范围,我们把这个范围称为虚拟地址空间。
  • 所谓的虚拟地址空间本质就是一个地址范围,表示程序的寻址能力。
  • 对于32位系统而言,虚拟地址空间从0x00000000~0xFFFFFFFF,也就是4G
    • 0 ~ 3G-1是归用户所使用,称为用户地址空间
    • 3G ~ 4G-1是归内核使用,称为内核地址空间
  • 对于64位系统而言,因为应用程序没有那么大的内存需求,所以不支持完全的64位虚拟地址
    • 0x0000 0000 0000 0000 ~ 0x0000 FFFF FFFF FFFF是用户地址空间
    • 0xFFFF 0000 0000 0000 ~ 0xFFFF FFFF FFFF FFFF是内核地址空间
    • 内核地址空间和用户地址空间直接是不规范地址空间,不允许使用,强制使用会出现段错误
    • 用户地址空间的代码不能直接访问内核空间的代码和数据,但可以通过系统调用进入内核态,间接与系统内核交互

以下是一个32位系统存储数据的示例图

在这里插入图片描述

从上图中可以看到每个进程都有自己独立的虚拟地址池,它们之间相互隔离,不会相互干扰或冲突,当给内核操作的虚拟地址没有在映射关系表中找到对应关系时,就会出现段错误

虚拟地址空间布局

  • 程序中不同性质的数据,加载到内存中,其虚拟地址会被映射到虚拟地址空间中不同区域

在这里插入图片描述

代码如下:

// 虚拟地址空间布局
#include <stdio.h>
#include <stdlib.h>const int const_global = 1;  // 常全局变量
int init_global = 2;  // 初始化全局变量
int uninit_global;  // 未初始化全局变量int main(int argc, char *argv[], char *envp[])
{static const int const_static = 3;  // 常静态变量static int init_static = 4;  // 初始化静态变量static int uninit_static; // 未初始化静态变量const int const_local = 5;  // 常局部变量int local;  // 局部变量char *string = "hello";  // 字面值常量int *heap = malloc(sizeof(int)); // 堆变量printf("----------参数和环境----------\n");printf("         命令行参数: %p\n", argv);printf("           环境变量: %p\n", envp);printf("------------栈区-------------\n");printf("         常局部变量: %p\n", &const_local);printf("           局部变量: %p\n", &local);printf("------------堆区-------------\n");printf("             堆变量: %p\n", heap);printf("------------BSS区-------------\n");printf("    未初始化全局变量: %p\n", &uninit_global);printf("    未初始化静态变量: %p\n", &uninit_static);printf("------------数据区-------------\n");printf("      初始化全局变量: %p\n", &init_global);printf("      初始化静态变量: %p\n", &init_static);printf("------------代码区-------------\n");printf("          常全局变量: %p\n", &const_global);printf("          常静态变量: %p\n", &const_static);printf("          字面值常量: %p\n", string);printf("               函数: %p\n", main);printf("-------------------------------\n");return 0;
}

内存映射的建立与解除

  • 没有与物理地址建立映射关系的虚拟地址,无法直接使用,如果强行使用被报段错误,我们可以通过系统调用mmap函数手动建立虚拟地址和物理地址之间的映射关系。
  • 补充:基本上所有的头文件都是放在这个路径下的:/usr/include
  • 下面那个函数需要引入mman.h这个头文件:#include <sys/mman.h>
  • mmap函数
    • void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
      • 功能:建立虚拟内存到物理内存或磁盘文件的映射
      • 参数
        • start:映射区虚拟内存的起始地址,NULL系统自动选定后返回。
        • length:映射区字节数,自动按页圆整,4k为一页。
        • prot:映射区操作权限,可取以下值,多选使用|隔开
          • PROT_READ:映射区可读
          • PROT_WRITE:映射区可写
          • PROT_EXEC:映射区可执行
          • PROT_NONE:映射区不可访问
        • flags:映射标志,可取以下值,多选使用|隔开
          • MAP_ANONYMOUS:匿名映射,将虚拟内存映射到物理内存中而非文件,使用这个就可以忽略df和offset参数,将这两个参数设为0即可
          • MAP_PRIVATE:对映射区的写操作只反映到缓冲区并不会真正写入文件,与MAP_SHARED二选一,不能同时存在
          • MAP_SHARED:对映射区的写操作直接反映到文件中
          • MAP_DENYWRITE:拒绝其他对文件的写操作
          • MAP_FIXED:若在start上无法创建映射,则失败(无此标志系统会自动调整)
        • fd:文件描述符,flags使用MAP_ANONYMOUS时,这里填0即可
        • offset:文件偏移量,自动按页(4K)对齐,flags使用MAP_ANONYMOUS时,这里填0即可
      • 返回值:成功返回映射区虚拟地址的起始地址,失败返回MAP_FAILED(-1)
  • munmap函数
    • int munmap(void *start, size_t length);
      • 功能:解除虚拟内存到物理内存或磁盘文件的映射
      • 参数:
        • start:映射区虚拟内存的起始地址
        • length:映射区字节数,自动按页圆整,4k为一页
      • 返回值:成功返回0,失败返回-1
      • munmap允许对映射区的一部分映射,但必须按页处理

使用示例:

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>int main(void)
{// 1. 建立映射: 返回值是void*类型,这里使用的是char*,内部会自动强转的char *start = mmap(NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);if(start == MAP_FAILED){perror("mmap");return -1;}// 2. 写入数据strcpy(start, "哈哈");printf("输出: %s\n", start);// 3. 解除一部分映射if(munmap(start, 4096) == -1){perror("munmap");return -1;}// strcpy(start, "呵呵");  // 这里测试使用了已经解除的虚拟地址,出现了 段错误 (核心已转储)// 4. 在剩下的那一部分中写入数据start += 4096;  // 首先先将start往上移strcpy(start, "嘿嘿");printf("输出: %s\n", start);// 5. 解除if(munmap(start, 4096) == -1){perror("munmap");return -1;}return 0;
}

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

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

相关文章

直播视频处理过程

视频其实就是快速播放一连串连续的图片。 每一张图片&#xff0c;我们称为一帧。只要每秒钟帧的数据足够多&#xff0c;也即播放得足够快。比如每秒 30 帧&#xff0c;以人的眼睛的敏感程度&#xff0c;是看不出这是一张张独立的图片的&#xff0c;这就是我们常说的帧率&#…

如何用一行CSS实现10种现代布局

现代 CSS 布局使开发人员只需按几下键就可以编写十分有意义且强大的样式规则。上面的讨论和接下来的帖文研究了 10 种强大的 CSS 布局&#xff0c;它们实现了一些非凡的工作。 超级居中&#xff1a;place-items: center 对于第一个“单行”布局&#xff0c;让我们解决所有 CSS…

分析数组,结构体在反汇编中存储

本文会在IDA中分析数组&#xff0c;结构体在内存中的存储 目录 IDA分析数组存储 IDA分析结构体存储 传递参数的方式 IDA分析数组存储 测试代码如下&#xff1a; /************************************************************************/ /*Author : 玄都大…

已解决 Kotlin Error: Null can not be a value of a non-null type String

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

Intel汇编在VS下开发的环境配置

1. 创建一个C/C的空项目 2. 创建汇编源码文件, 就是C文件改后缀为asm 3. 在生成依赖项一栏中选择自定义 4. 选择masm 5. 在源文件上右击选择属性 6. 这么设置一下 7. 为了让代码看的更舒服一些, 添加一些高亮插件 8. 安装AsmHighligher和AsmDude插件(非必须), 其中前者主要是高…

signal(SIGPIPE, SIG_IGN)

linux查看signal常见信号。 [rootplatform:]# kill -l1) HUP2) INT3) QUIT4) ILL5) TRAP6) ABRT7) BUS8) FPE9) KILL 10) USR1 11) SEGV 12) USR2 13) PIPE 14) ALRM 15) TERM 16) STKFLT 17) CHLD 18) CONT 19) STOP 20) TSTP 21) TTIN 22) TTOU 23) URG 24) XCPU 25) XFSZ 2…

【动态规划刷题 16】最长等差数列 (有难度) 等差数列划分 II - 子序列

1027. 最长等差数列 https://leetcode.cn/problems/longest-arithmetic-subsequence/ 给你一个整数数组 nums&#xff0c;返回 nums 中最长等差子序列的长度。 回想一下&#xff0c;nums 的子序列是一个列表 nums[i1], nums[i2], …, nums[ik] &#xff0c;且 0 < i1 <…

学Python的漫画漫步进阶 -- 第十一步.常用的内置模块

学Python的漫画漫步进阶 -- 第十一步.常用的内置模块 十一、常用的内置模块11.1 数学计算模块——math11.2 日期时间模块——datetime11.2.1 datetime类11.2.2 date类11.2.3 time类11.2.4 计算时间跨度类——timedelta11.2.5 将日期时间与字符串相互转换 11.3 正则表达式模块—…

音乐随行,公网畅享,群辉Audiostation给你带来听歌新体验!

文章目录 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是本教程使用环境&#xff1a;1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透&#xff0c;映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿&#xff0c;于是打开手…

代码随想录算法训练营第23期day2 | 977.有序数组的平方 、209.长度最小的子数组、59.螺旋矩阵II

目录 一、&#xff08;leetcode 977&#xff09;有序数组的平方 1.暴力解法 2.双指针法 二、&#xff08;leetcode 209&#xff09;长度最小的子数组 1.暴力解法 ​编辑2.滑动窗口 三、&#xff08;leetcode 59&#xff09;螺旋矩阵II 一、&#xff08;leetcode 977&…

ChatGLM 配置CUDA使用GPU本地训练

Cuda的下载及安装 cuda版本 由于显卡的不同,需要先查看我们显卡及驱动最高支持的cuda。 进入cmd输入nvidia -smi 版本支持向下兼容,为了保证能够和其他开发库版本兼容,这里使用的CUDN版本为11.6. cuda下载 CUDA Toolkit| NVIDIA Developer官网找到对应CUDA版本。(我这里…

基于Java的Base64编解码优化探讨

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

eclipse svn插件安装

1.进入eclipse的help->Eclipse Marketplace,如下图所示&#xff1a; 2.输入“svn”,再按回车&#xff0c;如下图&#xff1a; 3.这我选择的是 Subversive,点击后面的“install”按钮&#xff0c;如下图 Eclipse 下连接 SVN 库有两种插件 —— Subclipse 与 Subversive &…

java面向对象(八)

文章目录 一、abstract关键字的使用1.概念2. abstract修饰类:抽象类3.abstract修饰方法&#xff0c;抽象方法4.abstract使用上的注意点&#xff1a;5.抽象类的匿名子类 二、计算一段代码执行所花费的时间三、接口的使用1.接口的使用2.定义接口中的成员3.代码demo4.Java类可以实…

浙江大学《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作——2023学生开学季辉少许

浙江大学《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作——2023学生开学季辉少许

代码随想录算法训练营第一天(C)| 704. 二分查找 27. 移除元素

文章目录 前言一、704. 二分查找二、27. 移除元素三、34. 在排序数组中查找元素的第一个和最后一个位置总结 前言 这次是C&#xff1b; 代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素_愚者__的博客-CSDN博客 &#xff08;java&#xff09; 一、704. 二分查找 的优…

【Java 基础篇】Java线程安全与并发问题详解

多线程编程在Java中是一个常见的需求&#xff0c;它可以提高程序的性能和响应能力。然而&#xff0c;多线程编程也带来了一系列的线程安全与并发问题。在本文中&#xff0c;我们将深入探讨这些问题&#xff0c;以及如何解决它们&#xff0c;适用于Java初学者和基础用户。 什么…

在visual studio里安装Python并创建python工程

在2009年&#xff0c;云计算开始发力&#xff0c;Python、R、Go这些天然处理批量计算的语言也迅猛发展。微软在2010年&#xff0c;把Python当成一个语言包插件&#xff0c;集成到了visual studio 2010里。在"云优先&#xff0c;移动优先"的战略下&#xff0c;于2015年…

如何在 Excel 中进行加,减,乘,除

在本教程中&#xff0c;我们将执行基本的算术运算&#xff0c;即加法&#xff0c;减法&#xff0c;除法和乘法。 下表显示了我们将使用的数据以及预期的结果。 | **S / N** | **算术运算符** | **第一个号码** | **第二个号码** | **结果** | | 1 | 加法&#xff08;&#xff…

【Redis】深入探索 Redis 的哨兵(Sentinel)机制原理,基于 Docker 模拟搭建 Redis 主从结构和哨兵分布式架构

文章目录 一、对 Redis Sentinel 的认识1.1 什么是 Redis Sentinel1.2 为什么要使用 Redis Sentinel1.2.1 主从复制问题1.2.2 人工恢复主节点故障 二、Redis Sentinel 原理剖析2.1 Redis Sentinel 架构2.2 Raft 算法和领袖节点2.3 哨兵节点2.4 故障检测2.5 故障切换2.6 监控和通…