函数mmap是linux的一个系统函数。如下:

函数原型:void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

配套函数原型:int munmap(void *addr, size_t length);

头文件:#include <sys/mman.h>

返回值:成功返回创建的映射区的首地址;失败返回宏MAP_FAILED。

参数介绍:

addr:       建立映射区的首地址,由Linux内核指定。使用时,直接传递NULL。

length: 欲创建映射区的大小。

prot:      映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE。

flags:     标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区);

MAP_SHARED:  会将映射区所做的操作反映到物理设备(磁盘)上。

MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。

fd:         用来建立映射区的文件描述符。

offset: 映射文件的偏移(4k的整数倍)。

munmap函数:

同malloc函数申请内存空间类似的,mmap建立的映射区在使用结束后也应调用类似free的函数来释放。

返回值:成功:0; 失败:-1

接下来来使用mamp函数创建一个映射区:代码如下

#include
<stdio.h>

#include
<stdlib.h>

#include
<sys/mman.h>

#include
<sys/types.h>

#include
<unistd.h>

#include
<sys/stat.h>

#include
<fcntl.h>

#include
<string.h>

 

void sys_err(char
p[])//处理错误

{

    perror(p);

    exit(1);

}

int main()

{

    int o_ret = open("my_mmap.txt", O_CREAT | O_RDWR, 0644);//创建一个新文件

    if (-1 == o_ret) //错误检查是一个很好的习惯

    {

        sys_err("open ");

    }

 

    int f_ret = ftruncate(o_ret, 512);//在此文件大小的基础上扩展512字节大小,即文件现有大小为512字节(是个好函数,该记着。)

    if (-1 == f_ret)//成功返回0

    {

        sys_err("ftruncate ");

    }

 

    //———————————————————————————————————————————

    struct
stat statbuf;

    int s_ret = stat("my_mmap.txt", &statbuf);

    if (-1 == s_ret)

    {

        sys_err("stat ");

    }

    //———————————————————————————————————————————

    /*

    上面这段代码是我用来获取文件大小的方法,并没有一个系统函数能够直接获取文件的大小。所以我利用stat结构体存储文件的相关信息,然后获取到文件的大小:statbuf.st_size

    */

    char *const address = (char *)mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, o_ret, 0);

    //这里注意,我写的是char *const address这保证了address的值不变。

    if (MAP_FAILED == address)//若是mmap函数调用失败

    {

        sys_err("mmap ");

    }

    strcpy(address, "hallo, mmap");//能做这个操作是有先决条件的:映射区拥有写权限。

    int c_ret = close(o_ret);

    if (-1 == c_ret)

    {

        sys_err("close ");

    }

 

    int mun_ret = munmap(address, statbuf.st_size);//释放掉映射区。

    if (-1 == mun_ret)

    {

        sys_err("munmap ");

    }

 

    //printf("hello from mmap_test!\n");

    return 0;

}

很简单,这段代码编译之后就可以良好的运行下去。现在,我们来思考几个问题:

可以open的时候O_CREAT一个新文件来创建映射区吗?

如果open时O_RDONLY, mmap时PROT参数指定PROT_READ|PROT_WRITE会怎样?

文件描述符先关闭,对mmap映射有没有影响?

若是length参数大于文件的大小会怎样?

对mmap函数的返回值进行越界操作(++,–)会怎样?

如果文件偏移量为1000会怎样?

如果不检测mmap的返回值,会怎样?

答案:

可以,只要是正确的文件描述符传递给mmap都行

O_RDONLY代表只读,PROT_READ|PROT_WRITE代表读写,通过测试,我们就知道这是不行的,文件的权限代表着能对文件执行的操作;这里有一个结论:当第四个参数为MAP_SHARED时,映射区的权限应小于等于文件打开的权限。这样做的原因是出于对映射区的保护。而当第四个参数为MAP_PRIVATE时,就无所谓了,因为mmap中的权限时对内存的限制(映射区时在缓存区中创建的,缓存区是由内核管理调动的,不属于内存区域)。

只要mmap调用成功,文件就可以立即关闭,映射区的释放、操作与文件的关闭无关,因为映射区创建成功后时通过另一种方式(指针)来管理的。

注意:当用于创建映射区的文件大小为0时,不能创建映射区,会提示总线错误。所以:用于创建映射区的文件必须有实际的文件大小,并且创建的映射区大小不能超过文件大小。当出现总线错误的时候,多半是由于共享文件储存空间大小不正确引起的。

会造成调用munmap函数失败,不能释放映射区。所以推荐使用const关键字限定指针的值。

会出错,前面说过,文件的偏移量必须是4096(4k)的整数倍。

会死的很难看,因为使用mmap函数出错的几率很高。

在补充一下:

p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);看到标颜色的字词了吗?其中MAP_ANON是MAP_ANONYMOUS(MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。)的别称,不再被使用。因为我们创建一个匿名映射,所以我们不需要传递文件描述符。

函数mmap()的使用的更多相关文章

  1. mmap函数实现

    转自:https://www.cnblogs.com/huxiao-tee/p/4660352.htmlmmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址 ...

  2. 认真分析mmap:是什么 为什么 怎么用

    mmap基础概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.实现这样的映射关系后,进程就可以采用指 ...

  3. 认真分析mmap:是什么 为什么 怎么用【转】

    转自:http://www.cnblogs.com/huxiao-tee/p/4660352.html?utm_source=tuicool&utm_medium=referral 阅读目录 ...

  4. 6 高级IO函数

    6.1 pipe函数 pipe函数创建一个管道,用于实现进程间通信 #include<unistd.h> ]); 参数包含两个文件描述符fd[0]和fd[1],往fd[1]写入的数据可以从 ...

  5. Linux高性能server编程——高级I/O函数

     高级I/O函数 pipe函数 pipe函数用于创建一个管道,实现进程间的通信. #include <unistd.h> int pipe(int pipefd[2]); 通过pipe ...

  6. mmap学习

    mmap学习 内存页: Linux是以页为单位来管理物理内存的,一页大小一般等于4096字节.页容量越大,系统中可能存在的内存碎片就越多. mmap将一个磁盘上的文件或者对象映射进内存.文件被映射到多 ...

  7. Java网络编程和NIO详解8:浅析mmap和Direct Buffer

    Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...

  8. c语言中几个常见的库函数strlen、strcmp、strcat、strcpy、strncpy、memset、memcpy、memmove、mmap

    1.strlen() 1)计算给定字符串的长度,不包括’\0’在内 unsigned int strlen(const char *s) { assert(NULL != s);//如果条件不满足,则 ...

  9. Linux中文件I/O函数

    一.lseek函数 每个打开文件都有一个与其相关联的“当前文件偏移量”.它通常是一个非负整数,用以度量从文件开始处 计算的字节数.通常,读.写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数 ...

随机推荐

  1. 拓扑试验划分简单的静态VLAN

    拓扑图 说明: 把交换机连接到PC机的网口类型设置成为access 把交换机与交换机之间的网口类型设置成为truck 然后再给交换机每一个接口划分VLAN 操作如下: 交换机LSW1的配置: 进入输入 ...

  2. Jmeter(十六)Logic Controllers 之 Runtime Controller

    Runtime Controller-----运行时间控制器:控制其下的Sampler运行时间. 该控制器较为简单,官方文档也没作太多说明.照着Blazemeter写个例子: 运行,查看结果. 可以看 ...

  3. [UE4]Is Server判断是否在服务器端

  4. [UE4]根据时间、速度进行插值:Finterp to Constant

    一般在“Tick”事件中使用: Current:当前值 Target:期望的目标值 Delta Time:时间变化值. Interp Speed:插值速度 返回值:从“当前值”过渡到“期望的目标值”的 ...

  5. [UE4]利用取模运算达到循环遍历数组的目的

    X mod Y: 1.X<Y: X mod Y = X.计算记过永远都是等于X 2.X=Y:X mod Y = 0.重新回到数组第一个索引位置

  6. ​游戏设计思考:对COK的理解和思考

    转自:http://www.gameres.com/804983.html 一.前言 发此文的起因是最近加入了一个游戏研究群,受到大家对游戏研究热情的感染,也想将自己对游戏的理解和感悟发出来和大家一起 ...

  7. tp3.2 支付宝手机网站支付

    手机网站支付接口,支付宝官方文档:https://b.alipay.com/signing/productSet.htm?navKey=all 第一步: 1)登陆支付宝企业账号 进入支付宝官网 ,登陆 ...

  8. 安装MySQL半同步复制

    一.简介 从MySQL5.5开始,MySQL以插件的形式支持半同步复制.如何理解半同步呢?首先我们来看看异步,全同步的概念 异步复制(Asynchronous replication) MySQL默认 ...

  9. h5登录页面

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  10. 在同一个Linux上配置多个git账户

    1.首先在~/.ssh目录下执行 ssh-keygen -t rsa -C "miaoying.new@qq.com" 其中 -C "miaoying.new@qq.co ...