Linux C\C++编程-建立文件和内存映射

【图书推荐】《Linux C与C++一线开发实践(第2版)》_linux c与c++一线开发实践pdf-CSDN博客

《Linux C与C++一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书

LinuxC\C++编程技术_夏天又到了的博客-CSDN博客

所谓文件和内存映射,就是将普通文件映射到进程地址空间,然后进程就可以像访问普通内存一样对文件进行访问,而不必再进行调用read或write等操作。系统提供了函数mmap将普通文件映射到内存中,该函数声明如下:

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

其中,参数start为映射区的起始地址,通常为NULL(或0),表示由系统自己决定映射到什么地址;length表示映射数据的长度,即文件需要映射到内存中的数据的大小;prot表示映射区保护方式,取下列某个值或者它们的组合:

  • PROT_EXEC:映射区可被执行。
  • PROT_READ:映射区可读取。
  • PROT_WRITE:映射区可写入。
  • PROT_NONE:映射区不可访问。

参数flags用来指定映射对象的类型、映射选项和映射页是否可以共享,它的值可以是一个或者多个位的组合,可选值如下:

  • MAP_FIXED:如果参数start指定了需要映射到的地址,而所指定的地址无法成功建立映射,映射就会失败。通常不推荐使用此设置,而是将start设置为NULL(或0),由系统自动选取映射地址。
  • MAP_SHARED:共享映射区域,映射区域允许其他进程共享,对映射区域写入数据将会写入原来的文件中。
  • MAP_RIVATE:对映射区域进行写入操作时会产生一个映射文件的复制,即写入复制(copy on write),而读操作不会影响此复制。对此映射区的修改不会写回原来的文件,即不会影响原来文件的内容。
  • MAP_ANONYMOUS:建立匿名映射,映射区不与任何文件关联,而且映射区无法与其他进程共享。
  • MA_DENYWRITE:对文件的写入操作将被禁止,不允许直接对文件进行操作。
  • MAP_LOCKED:将映射区锁定,防止页面被交换出内存。

参数flags必须为MAP_SHARED或者MAP_PRIVATE二者之一的类型。MAP_SHARED类型表示多个进程使用的是一个内存映射的副本,任何一个进程都可以对此映射进行修改,其他的进程对其修改是可见的。而 MAP_PRIVATE则是多个进程使用的文件内存映射,在写入操作后,会复制一个副本给修改的进程,多个进程之间的副本是不一致的。

参数fd表示文件描述符,一般由open()函数返回;参数offset表示被映射数据在文件中的起点。

mmap()映射后,让用户程序直接访问设备内存,相较于在用户空间和内核空间互相复制数据,其效率更高,因此在要求高性能的应用中比较常用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmap,mmap的实现和硬件有关。

下面这个例子显示了把文件映射到内存的方法。

【例4.11】文件与内存映射

(1)打开Visual Studio Code,新建文本文件,输入代码如下:

#include <sys/mman.h> /* for mmap and munmap */  
#include <sys/types.h> /* for open */  
#include <sys/stat.h> /* for open */  
#include <fcntl.h>     /* for open */  
#include <unistd.h>    /* for lseek and write */  
#include <stdio.h>  
  
int main(int argc, char **argv)  
{  
	int fd;  
	char *mapped_mem, * p;  
	int flength = 1024;  
	void * start_addr = 0;  
  
	fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);  
	flength = lseek(fd, 1, SEEK_END);  
	write(fd, "\0", 1); /* 在文件最后添加一个空字符,以便下面的printf正常工作 */  
	lseek(fd, 0, SEEK_SET);  
	mapped_mem =(char*) mmap(start_addr,
		flength,
		PROT_READ,        			// 允许读  
		MAP_PRIVATE,       			// 不允许其他进程访问此内存区域  
		fd,
		0);  
      
	/* 使用映射区域 */  
	printf("%s\n", mapped_mem); /* 为了保证这里工作正常,参数传递的文件名最好是一个文本文件 */  
	close(fd);  
	munmap(mapped_mem, flength);  
	return 0;  
}  

(2)保存代码为test.cpp,上传到Linux,在命令行下编译并运行:

# g++ test.cpp -o test
# ./test myfile.txt 
hello
boy

可以发现,程序把文件中的内容映射到内存后,再把该内存区域打印出来,显示的正是文件中的内容。其中,myfile.txt是自己新建的文本文件。

上面的方法因为用了PROT_READ,所以只能读取文件里的内容,不能修改,如果换成PROT_WRITE,就可以修改文件的内容了;又由于用了MAAP_PRIVATE,因此此进程只能使用此内存区域,若换成MAP_SHARED,则可以被其他进程访问,请看下例。

【例4.12】修改文件的内存映像

(1)打开Visual Studio Code,新建文本文件,输入代码如下:

#include <sys/mman.h> /* for mmap and munmap */  
#include <sys/types.h> /* for open */  
#include <sys/stat.h> /* for open */  
#include <fcntl.h>     /* for open */  
#include <unistd.h>    /* for lseek and write */  
#include <stdio.h>  
#include <string.h> /* for memcpy */  
      
int main(int argc, char **argv)  
{  
	int fd;  
	char *mapped_mem, * p;  
	int flength = 1024;  
	void * start_addr = 0;  
      
	fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);  
	flength = lseek(fd, 1, SEEK_END);  
	write(fd, "\0", 1); // 在文件最后添加一个空字符,以便下面的printf正常工作 
	lseek(fd, 0, SEEK_SET);  
	start_addr = (void*)0x80000;  
	mapped_mem = (char*)mmap(start_addr,
		flength,
		PROT_READ|PROT_WRITE,        // 允许写入  
		MAP_SHARED,       // 允许其他进程访问此内存区域  
		fd,
		0);  
      
    // 使用映射区域
	printf("%s\n", mapped_mem); // 为了保证这里正常工作,参数传递的文件名最好是一个文本文件  
	while ((p = strstr(mapped_mem, "hello"))) { // 此处来修改文件内容,hello必须在文件中已经有了
		memcpy(p, "Linux", 5);  // 我们把hello改为Linux
		p += 5;  
	}  
          
	close(fd);  
	munmap(mapped_mem, flength);  
	return 0;  
}  

(2)保存代码为test.cpp,上传到Linux,在命令行下编译并运行:

# g++ test.cpp -o test
# ./test myfile.txt 
hello
boy

再次查看myfile.txt,可以发现内容变了:

# cat myfile.txt 
Linux
boy

说明我们修改内存映像成功了。

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

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

相关文章

15-spring整合mybatis方式一

spring整合mybatis 方式一【重要】 步骤: 1.导入相关jar包 junit mybatis mysql数据库 spring相关的 aop织入 mybatis-spring 【new】 junit junit 4.12 mysql mysql-connector-java 8.0.23 org.mybatis mybatis 3.5.2 org.springframework spring-webmvc 5…

基于深度学习的视觉检测小项目(十五) 用户的登录界面

用户管理离不开的是消息框&#xff08;QMessageBox&#xff09;和对话框&#xff08;QDialog&#xff09;&#xff0c;比如对话框用于用户名和密码输入&#xff0c;消息框用于提示登录成功、密码错误。 • 基础知识&#xff1a;PySide6&#xff08;PyQT5&#xff09;的常用对话…

什么是COLLATE排序规则?

在当今数字化世界中&#xff0c;数据的整理、比较和排序是至关重要的。在数据库管理和编程语言中&#xff0c;我们经常需要对字符串进行排序&#xff0c;以展示或处理信息。为了实现这一点&#xff0c;各种系统和工具提供了排序规则&#xff0c;其中COLLATE排序规则就是其中的一…

Linux:信号的保存[2]

1.信号在内核中的表示 因为是三种内核的数据结构&#xff0c;操作系统就可以通过操作这些数据结构提供接口。 如果一个信号没有产生&#xff0c;并不妨碍它可以先被阻塞。 当同一时刻发送大量相同信号时&#xff0c;会丢失。 2.信号的捕捉&#xff08;重点&#xff09; 信号产…

顺序表和链表(详解)

线性表 线性表&#xff08; linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。…

【电脑无法通过鼠标和键盘唤醒应该怎么办】

【电脑无法通过鼠标和键盘唤醒应该怎么办】 方法一(有时候不起作用):方法二(方法一无效时,使用方法二): 方法一(有时候不起作用): 方法二(方法一无效时,使用方法二):

动态规划(路径问题)

62. 不同路径 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 动态规划思想第一步&#xff1a;描述状态~ dp[i][j]&#xff1a;表示走到i&#xff0c;j位置时&#xff0c;一共有多少种方法~ 动态规划思想第二步&#xff1a;状态转移方程~ 动态规划思想第三步&#xf…

vue + element-ui 组件样式缺失导致没有效果

失效 代码&#xff1a; 修改方法&#xff1a; 在main.js文件里面加上&#xff1a; import element-ui/lib/theme-chalk/index.css; 最后&#xff1a;

Go 切片:用法和本质

要想更好的了解一个知识点&#xff0c;实战是最好的经历。 题目 我这里放一道题目&#xff1a; package mainimport "fmt"func SliceRise(s []int) {s append(s, 0)for i : range s {s[i]}fmt.Println(s) }func SlicePrint() {s1 : []int{1, 2}s2 : s1s2 append…

Spring MVC:设置响应

目录 引言 1. 返回静态页面 1.1 Spring 默认扫描路径 1.2 RestController 1.2.1 Controller > 返回页面 1.2.2 ResponseBody 2. 返回 HTML 2.1 RequestMapping 2.1.1 produces(修改响应的 Content-Type) 2.1.2 其他属性 3. 返回 JSON 4. 设置状态码 4.1 HttpSer…

基于Spark的共享单车数据存储系统的设计与实现_springboot+vue

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

在Unity中使用大模型进行离线语音识别

文章目录 1、Vosk下载下载vosk-untiy-asr下载模型在项目中使用语音转文字音频转文字2、whisper下载下载unity项目下载模型在unity中使用1、Vosk 下载 下载vosk-untiy-asr Github链接:https://github.com/alphacep/vosk-unity-asr 进不去Github的可以用网盘 夸克网盘链接:h…

【计算机网络】- 应用层HTTP协议

目录 初识HTTP 什么是HTTP 版本 HTTPS 模型 HTTP抓包工具 为什么使用 抓包工具的下载 下载后的重要操作 Fiddler的使用 HTTP请求与响应的基本格式 HTTP请求基本格式​编辑 HTTP响应基本格式 协议格式总结❗️❗️❗️​编辑 HTTP 详解 认识 URL URL基本格式 …

记一次IDOR 和访问控制缺失漏洞挖掘

视频教程在我主页简介和专栏里 测试 IDOR&#xff08;不安全的直接对象引用&#xff09; 漏洞时&#xff0c;我会使用一系列工具&#xff0c;确保不会遗漏任何问题。以下是我的测试方法&#xff1a; 设置 Firefox 和 Pwnfox&#xff1a; 1、我使用 Firefox 浏览器&#xff0c…

GS论文阅读--Hard Gaussian Splatting

前言 本文也是对高斯点云的分布进行优化的&#xff0c;看&#xff01; 文章目录 前言1.背景介绍2.关键内容2.1 位置梯度驱动HGS2.2 渲染误差引导HGS 3.文章贡献 1.背景介绍 在训练过程中&#xff0c;它严重依赖于视图空间位置梯度的平均幅度来增长高斯以减少渲染损失。然而&…

JS基础-操作数组(7)

一.增删改查 1.改 重新赋值 2.增 arr.puch() 末尾追加 arr.unshift() 开头追加 a)案例&#xff1a;数组筛选 3.删除 arr.pop() 删除最后一个元素 arr.shift() 删除第一个元素 splice&#xff08;&#xff09; 删除指定元素

C++otlv4连接sql serveer使用记录(注意点)

C使用otlv4在做插入时&#xff0c;有一些设计的坑需要注意 插入数据&#xff1a; 当要给表中插入单个字符时&#xff0c;数据库表设计使用varchar(1)是合理的&#xff0c;但是otlv4一直报错char。 后续查很久才知道&#xff0c;otlv4所写的绑定的字符数组的长度应该实际数组…

Chapter 6.5-Adding a classification head

Chapter 6 -Fine-tuning for classification 6.5-Adding a classification head 为进行分类微调&#xff0c;须修改预训练的大语言模型&#xff08;LLM&#xff09;。我们将原本把隐藏表征映射到含50,257个词的词表的输出层&#xff0c;替换为一个更小、仅映射到 “0&#xff…

洛谷题目 P1006 [NOIP2008 提高组] 传纸条 题解 (本题较难)

题目传送门&#xff1a; P1006 [NOIP2008 提高组] 传纸条 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 前言&#xff1a; 本题来源于2008年NOIp 提高组竞赛题目&#xff1a;传纸条&#xff0c;本题涉及到动态DP、图论里的费用流知识点&#xff0c;学过图论的都应该对这道题…

智能电动汽车 --- 人工智能(AI)入门

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…