Archive for 2011 年 1 月

cut命令和paste命令

19 1 月, 2011
cut命令

顾名思义,cut命令就是从文本文件或从某个命令的输出数据中裁剪(析取)出想要的数据域。cut命令一般使用的方式为:

cut -cchars file

其中,-cchar中的-c为cut命令的常用选项,表示从file文件的每一行中都cut出chars这段文字。。chars的取值较为灵活,分为以下几种情况。

cut -c5 file:析取file文件每行的第5个字符;

cut -c5,7 file:析取file文件每行第5和第7个字符;

cut -c6-8 file:析取file文件每行第6到第8个字符;

cut -c6- file:析取file文件每行第6个到行尾之间的字符;

cut -c-3 file:析取file文件每行行首到第三个字符之间的字符;

如果cut命令中未指定file,则将标准输入作为cut命令的析取对象。比如:

edsionte@edsionte-desktop:~$ ls -l
总用量 1680
drwx------  2 edsionte edsionte   4096 2011-01-10 20:38 android_code
-rwxrwxrwx  1 edsionte edsionte   7138 2011-01-13 08:42 a.out
drwxr-xr-x  2 edsionte edsionte   4096 2011-01-16 21:46 assembly
drwxr-xr-x  2 edsionte edsionte   4096 2011-01-11 09:58 bin
drwx------ 24 edsionte edsionte   4096 2011-01-17 11:35 code
edsionte@edsionte-desktop:~$ ls -l | cut -c1-9
总用量
drwx-----
-rwxrwxrw
drwxr-xr-
drwxr-xr-
drwx-----

上述cut命令中,将ls命令的输出作为cut命令的输入。产生的结果是析取出每列数据的第1到第9个字符,也既是每个文件的访问权限。下面的例子通过逗号隔开两个数值列表,分别析取出文件访问权限和文件名。

edsionte@edsionte-desktop:~$ ls -l
总用量 1680
drwx------  2 edsionte edsionte   4096 2011-01-10 20:38 android_code
-rwxrwxrwx  1 edsionte edsionte   7138 2011-01-13 08:42 a.out
drwxr-xr-x  2 edsionte edsionte   4096 2011-01-16 21:46 assembly
drwxr-xr-x  2 edsionte edsionte   4096 2011-01-11 09:58 bin
drwx------ 24 edsionte edsionte   4096 2011-01-17 11:35 code
edsionte@edsionte-desktop:~$ ls -l | cut -c1-9,56-
总用量
drwx----- android_code
-rwxrwxrw a.out
drwxr-xr- assembly
drwxr-xr- bin
drwx----- code

-d和-f选项

通过上述的例子可以看到,如果单纯使用-c选项,则必须很清楚所要解析字符在每行中的位置;另外,-c选项适用从格式固定的文件或命令输出中解析出所需要的字符。如果文件数据的组织格式不固定,则很难使用-c选项从每行中都解析出所需的字符。

比如我们常常会遇到这样的个人信息,包含姓名,性别,城市,爱好,电话:

edsionte:male:xian:music:18717375182
zhyun:famle:beijing:basketball:18654737473
liting:male:zhangjiajie:tableball:15784859345

现在如果要解析出姓名,使用-c选项则不可能做到。不过该文件有一个特点,每行信息中的每个字段都使用分号隔开,此时我们就可以使用-f和-d选项:

cut -ddchar -ffields file

dchar表示我们析取字段时所依据的分隔符;fields标示我们所要析取的字段序号,可用逗号隔开多个字段序号。对于上面的例子,我们可以这么做:

edsionte@edsionte-laptop:~/shelltest$ cut -d: -f1 info
edsionte
zhyun
liting

cut命令将制表符(\t)作为默认的字段分隔符,如果某个文件用制表符作为每行各个字段的分隔符,则使用cut -ffield file即可析取相应字段。

paste命令

与cut命令相反,paste命令可以将多个文件对应行的数据连接在一起,数据之间使用制表符隔开。合并后的结果默认在标准输出中输出。该命令基本使用方法为:

paste files

比如将下面的name和gender合并在一起:

edsionte@edsionte-desktop:~/shelltest$ cat name
edsionte
wangsen
zhanyu
edsionte@edsionte-desktop:~/shelltest$ cat gender
m
m
f
f
m
edsionte@edsionte-desktop:~/shelltest$ paste name gender
edsionte	m
wangsen	m
zhanyu	f
	f
	m

可以看到,由于name文件中只有三行数据,因此gender文件中最后两行和空字符合并在一起。

-d选项

通过-d选项可以指定任意分隔符来隔开不同文件每行的内容,基本使用方法为:

paste -dchars files

dchar可以取多个分隔符,每个分隔符依次隔开files中每个文件每行的数据。比如:

edsionte@edsionte-desktop:~/shelltest$ paste -d~, name gender number
edsionte~m,123
wangsen~m,456
zhanyu~f,789
~f,
~m,

从这个例子也可以看出,name和number文件的第4和第5行的数据均为空。

-s选项

通过这个选项可以将一个文件每行的数据都合并在一起。比如:

edsionte@edsionte-desktop:~/shelltest$ ls
file1  file3  file5  file7  gender  number
file2  file4  file6  file8  name
edsionte@edsionte-desktop:~/shelltest$ ls | paste -s -d@
file1@file2@file3@file4@file5@file6@file7@file8@gender@name@number

对于上述两个命令,使用-d选项时最好将分隔符放在单引号中。原因很简单,比如:

edsionte@edsionte-desktop:~/shelltest$ ls | paste -s -d;
paste:选项需要一个参数 -- d
请尝试执行"paste --help"来获取更多信息。

原因是shell并没有将;作为分隔符,而是认为它是paste命令的结束标志。这里的原因跟转义字符差不多,因为此时我们需要使用;的本意。加上单引号即可成功执行上述命令:

edsionte@edsionte-desktop:~/shelltest$ ls | paste -s -d';'
file1;file2;file3;file4;file5;file6;file7;file8;gender;name;number

目录文件的访问权限

17 1 月, 2011

目录的访问权限

在linux当中,文件分为多种类型。比如普通文件,目录文件和符号链接文件等。我们通常所说的“文件”则默认为普通文件,也就是指文本文件和二进制文件(关于文件的分类描述,可参看这里)。

每一类文件还有相应的访问权限。对于一个文件而言,所谓的访问权限是指文件访问者是否对该文件具有读、写或执行的权利。另外,linux是一个多用户的操作系统,它将用户分为三种:用户(u,即文件所有者),用户所在组(g),其他用户(o)。因此,对于不同身份的用户,也就应当对一个文件有不同的访问权限。所以,每个文件有9个访问权限。

对于目录文件的权限,他和普通文件稍有不同;

读:可以读取该目录,从中获得该目录中所有文件名,但不能读取到每个文件的状态;
执行:可以对该目录进行搜索,也就是通过该目录可以搜索其内的特定文件名;
写:可以在该目录下新建或删除文件,但是首先必须对该目录拥有执行权限。如果该目录没有执行权限就不能对该目录下的文件进行搜索,新建或删除文件也就无从谈起;

测试

对于目录的访问权限,从文字描述的角度并不能理解的很清楚。因此,通过不断的测试才能理解这些访问权限对目录的作用效果。我们假设在edsionte主目录下有一个dirtest目录,其基本信息如下:

edsionte@edsionte-desktop:~$ ls -ld dirtest/
drwxr-xr-x 4 edsionte edsionte 4096 2011-01-17 11:06 dirtest/
edsionte@edsionte-desktop:~$ ls -l dirtest/
总用量 16
drwxr-xr-x 3 edsionte edsionte 4096 2011-01-15 16:10 cdev
-rw-r--r-- 1 edsionte edsionte  975 2010-10-17 22:06 pms.c
drwxr-xr-x 2 edsionte edsionte 4096 2011-01-13 20:49 shell
-rw-r--r-- 1 edsionte edsionte   19 2011-01-13 21:08 test.c

接下来的测试都是以edsionte用户身份对这个目录进行各种命令测试的,具体如下:

1.通过ls dirtest命令,可参看该目录下的文件名。因为这个目录具有读权限;

edsionte@edsionte-desktop:~$ ls dirtest/
cdev  pms.c  shell  test.c

2.先使得dirtest没有执行,再执行ls命令。可以看到,虽然可以读到每个文件名,但是每个文件的属性确无法获得;

edsionte@edsionte-desktop:~$ chmod a-x dirtest/
edsionte@edsionte-desktop:~$ ls dirtest/ -l
ls: 无法访问dirtest/shell: 权限不够
ls: 无法访问dirtest/test.c: 权限不够
ls: 无法访问dirtest/pms.c: 权限不够
ls: 无法访问dirtest/cdev: 权限不够
总用量 0
d????????? ? ? ? ?                ? cdev
-????????? ? ? ? ?                ? pms.c
d????????? ? ? ? ?                ? shell
-????????? ? ? ? ?                ? test.c

3.由于没有执行权限,无法搜索判断dirtest目录下是否已存在newfile.c文件,因此无法完成touch命令,即便该目录具有写权限;

edsionte@edsionte-desktop:~$ ls -ld dirtest/
drw-r--r-- 4 edsionte edsionte 4096 2011-01-17 11:06 dirtest/
edsionte@edsionte-desktop:~$ touch dirtest/newfile.c
touch: 无法创建"dirtest/newfile.c": 权限不够

对于目录文件,也是如此:

edsionte@edsionte-desktop:~$ chmod a-x dirtest/
edsionte@edsionte-desktop:~$ mkdir ./dirtest/newdir
mkdir: 无法创建目录"./dirtest/newdir": 权限不够

4.对该目录加上执行权限后,2和3中所遇到的问题都可以解决:

edsionte@edsionte-desktop:~$ chmod a+x dirtest/
edsionte@edsionte-desktop:~$ touch dirtest/newfile.c
edsionte@edsionte-desktop:~$ ls -l dirtest/
总用量 16
drwxr-xr-x 3 edsionte edsionte 4096 2011-01-15 16:10 cdev
-rw-r--r-- 1 edsionte edsionte    0 2011-01-17 11:36 newfile.c
-rw-r--r-- 1 edsionte edsionte  975 2010-10-17 22:06 pms.c
drwxr-xr-x 2 edsionte edsionte 4096 2011-01-13 20:49 shell
-rw-r--r-- 1 edsionte edsionte   19 2011-01-13 21:08 test.c

5.继续使得dirtest没有执行权限,由于不能读取dirtest下的目录cdev,也就更不能读取cdev目录下的文件,即便cdev具有可读可执行权限;

edsionte@edsionte-desktop:~$ ls -ld dirtest/cdev/
drwxr-xr-x 3 edsionte edsionte 4096 2011-01-15 16:10 dirtest/cdev/
edsionte@edsionte-desktop:~$ chmod a-x dirtest/
edsionte@edsionte-desktop:~$ ls -ld dirtest/cdev/
ls: 无法访问dirtest/cdev/: 权限不够
edsionte@edsionte-desktop:~$ ls -l dirtest/cdev/
ls: 无法访问dirtest/cdev/: 权限不够

6.如果dirtest有执行权限却没有写权限,则不能创建新文件。这一点很好理解;

edsionte@edsionte-desktop:~$ ls -ld dirtest/
dr-xr-xr-x 4 edsionte edsionte 4096 2011-01-17 11:36 dirtest/
edsionte@edsionte-desktop:~$ mkdir ./dirtest/newdir
mkdir: 无法创建目录"./dirtest/newdir": 权限不够

7.如果dirtest有写权限却没有执行权限,则不能在该目录下删除文件;

edsionte@edsionte-desktop:~$ chmod a-x dirtest/
edsionte@edsionte-desktop:~$ ls -ld dirtest/
drw-rw-rw- 4 edsionte edsionte 4096 2011-01-17 11:36 dirtest/
edsionte@edsionte-desktop:~$ rm ./dirtest/newfile.c
rm: 无法删除"./dirtest/newfile.c": 权限不够

8.如果dirtest目录有可写权限没有可执行权限,虽然可以打开该目录下的文件test.c,但是对其修改后不能保存;

edsionte@edsionte-desktop:~$ ls dirtest/
cdev  newfile.c  pms.c  shell  test.c
edsionte@edsionte-desktop:~$ chmod a-x dirtest/
edsionte@edsionte-desktop:~$ vim ./dirtest/test.c

9.如果要修改dirtest目录下的文件test.c,对于dirtest目录而言,必须具备执行权限;而该目录的写权限则与test.c的修改无关;

通过上面的测试,我们可以得出下面的结论:

1.对一个目录进行读操作,即指读该目录下的文件名;

2.对一个目录的“写”包括在该目录下删除、新建文件;更重要的是,只有该目录有可执行权限时,写操作才可以进行,否则,不能获取该目录下除文件名之外的任何文件状态信息;

3.如果在一次文件操作中,只要涉及到对目录的搜索,则该目录必须具备执行权限,否则写权限就无法进行;

一个目录的执行权限可以用下面的比喻来解释。一个目录就好像是一道门,该目录中的文件就是你想要的珍宝。并且,该门之后可能还会有其他门的存在。目录的可执行权限相当于打开这把门的钥匙,只有持有这把钥匙,你才能打开这扇目录之门。打开门后,你可能会拿走一些宝石(删除文件),或者放入一些宝石(新建文件)等。否则,你只能隔门相望门后的宝石了(只能读取文件名)。

字符设备驱动再学习

15 1 月, 2011

本学期一直在学习linux下到设备驱动开发,字符设备驱动是设备驱动开发中最基本和重要的一部分。前几天的考试让我意识到对这部分的内容理解的还不是很清楚,因此,很有必要再次理解学习字符设备驱动。

本文以全局内存字符设备globalmem为例,说明字符设备驱动的结构以及编写方法。

1.字符设备的数据结构

在linux内核中使用struct cdev来表示一个字符设备,如下:

//在linux/include/linux/cdev.h中
  12struct cdev {
  13        struct kobject kobj;
  14        struct module *owner;
  15        const struct file_operations *ops;
  16        struct list_head list;
  17        dev_t dev;
  18        unsigned int count;
  19};

下面对该数据结构的字段作简单解释:

owner:该设备的驱动程序所属的内核模块,一般设置为THIS_MODULE;
ops:文件操作结构体指针,file_operations结构体中包含一系列对设备进行操作的函数接口;
dev:设备号。dev_t封装了unsigned int,该类型前12位为主设备号,后20位为次设备号;

cdev结构是内核对字符设备驱动的标准描述。在实际的设备驱动开发中,通常使用自定义的结构体来描述一个特定的字符设备。这个自定义的结构体中必然会包含cdev结构,另外还要包含一些描述这个具体设备某些特性到字段。比如:

struct globalmem_dev
{
	struct cdev cdev; /*cdev struct which the kernel has defined*/
	unsigned char mem[GLOBALMEM_SIZE]; /*globalmem memory*/
};

该结构体用来描述一个具有全局内存的字符设备。

2.分配和释放设备号

在linux中,对于每一个设备,必须有一个惟一的设备号与之相对应。通常会有多个设备共用一个主设备号,而具体每个设备都唯一拥有一个次设备号。总的来看,每个设备都唯一的拥有一个设备号。前面已经提到,内核使用dev_t类型来表示一个设备号,对于设备号有以下几个常用的宏:

//在linux/include/linux/kdev_t.h中
7#define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))
8#define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))
9#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

上述三个宏的功能分别为:通过设备号获取主设备号,通过设备号获取次设备号,通过主次设备好获取设备号。

在设备驱动程序中,一般会首先向系统申请设备号。linux中设备号的申请都是一段连续的设备号,这些连续的设备号都有共同的主设备号。设备号的申请有两种方法,若提前设定了主设备号则再接着申请若干个连续的次设备即可;若未指定主设备号则直接向系统动态申请未被占用到设备号。由此可以看出,如果使用第一种方法,则可能会出现设备号已被系统中的其他设备占用的情况。

上出两种申请设备号的方法分别对应以下两个申请函数:

  //在linux/fs/char_dev.c中
 196int register_chrdev_region(dev_t from, unsigned count, const char *name)
 232int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
 233                        const char *name)

上述两个函数都可以申请一段连续的设备号。前者适用已知起始设备号的情况(通过MADEV(major,0)可以获得主设备号为major的起始设备号);后者使用于动态申请设备号的情况。如果想申请一个设备号,则将函数中的参数count设为1即可。关于这两个函数的详细源码分析,可参考这里

3.Linux字符设备驱动的组成

实现一个基本的字符设备驱动需要完成以下几部分:字符设备驱动模块的加载卸载函数和实现file_operations结构中的成员函数。

3.1.file_operations结构体

file_operations结构体中包含许多函数指针,这些函数指针是字符设备驱动和内核的接口。,实现该结构中的这些函数也是整个字符设备驱动程序的核心工作。file_operations结构中的每个函数都对应一个具体的功能,也就是对设备的不同操作。不过,这些函数是在内核模块中实现的,最终会被加载到内核中和内核一起运行。因此,用户态下的程序是不能直接使用这些函数对相应设备进行操作的。

学过系统调用后,你就会知道,比如当应用程序通过系统调用read对设备文件进行读操作时,最终的功能落实者还是设备驱动中实现的globalmem_read函数。而将系统调用read和globalmem_read函数扯上关系的则是struct file_operations。具体的操作是:

static const struct file_operations globalmem_fops =
{
	.owner = THIS_MODULE,
	.read = globalmem_read,
	.write = globalmem_write,
	.open = globalmem_open,
	.release = globalmem_release,
};

3.2.实现加载和卸载函数

由于字符设备驱动程序是以内核模块的形式加载到内核的,因此该程序中必须有内核模块的加载和卸载函数。通常,字符设备驱动程序的加载函数完成的工作有设备号的申请、cdev的注册。具体的过程可参考下图:

globalmem_init流程图(点击看大图)

从上述的图中可以看到,在内核模块加载函数中主要完成了字符设备号的申请。将字符设备注册到系统中是通过加载函数中的globalmem_setup_cdev函数来完成的。该函数具体完成的工作可以参考下图:

globalmem_setup_cdev流程图

结合上图,接下来参看globalmem_setup_cdev函数的具体代码。由cdev_init中,除了初始化cdev结构中的字段,最重要的是将globalmem_fops传递给cdev中的ops。

static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
	int ret;
	int devno = MKDEV(globalmem_major, index);

	cdev_init(&dev->cdev, &globalmem_fops);
	dev->cdev.owner = THIS_MODULE;
	dev->cdev.ops = &globalmem_fops;
	ret = cdev_add(&dev->cdev, devno, 1);
	if(ret){
		printk("adding globalmem error");
	}
}

通过上述的几步,就可以完成字符设备驱动加载函数。对于字符设备卸载函数而言,所作的工作就是加载函数功能的逆向:将cdev从系统中注销;释放设备结构体所占用的内存空间;释放设备号。具体可参看代码:

static void __exit globalmem_exit(void)
{
	/*free struct cdev*/
	cdev_del(&dev->cdev);
	/*free the memory of struct globalmem_dev*/
	kfree(dev);
	/*free the devno*/
	unregister_chrdev_region(MKDEV(globalmem_major,0), 1);
}

3.3.对file_operaions成员函数的实现
最基本的成员函数包括open、release、read和write等函数。对这些函数的具体实现还要根据具体的设备要求来完成。在本文所述的全局内存字符设备驱动中,我们要实现的是功能是在用户程序中对这字符设备中的这块全局内存进行读写操作。读写函数的具体功能可参考下图:

对于open和release可以不做具体实现,当用户态程序打开或释放设备文件时,会自动调用内核中通用的打开和释放函数。

这样,一个基本的字符设备驱动程序就完成了。本文所述实例是一个有代表性的通用模型,可以在理解本程序的基础上继续增加其他功能。

虚拟映射和mmap()

12 1 月, 2011

虚存映射

我们知道,程序是存储在磁盘上到静态文件;进程是对程序到一次运行过程。在进程开始运行时,进程的代码和数据等内容必须装入到进程用户空间到适当区域。这些区域也就是所谓的代码段和数据段等,而被装入的数据和代码等内容被称为进程的可执行映像。从上面都描述中可以发现,进程在运行时并不是将程序一下子就装入到物理内存,而只是将程序装入到进程的用户空间,这个装入的过程称为虚存映射。

一个源程序在成为可执行文件的过程中会经历预处理、编译、汇编和链接四个阶段。因此,进程要成功运行不仅要在其用户空间装入进程映像,也要装入该进程所用到到函数库以及链接程序等。所以,一个进程到用户空间就被分为若干个内存区域。linux使用mm_struct结构来描述一个进程到用户地址空间,使用vm_area_struct结构来描述进程地址空间中的一个内存区域。因此,一个vm_area_struct结构可能代表进程到数据段,也可能代表链接程序到代码段等。

进程的虚存映射所做的只是将磁盘上到文件映射到该进程的用户地址空间,并没有建立虚拟内存到物理内存的映射。当某个可执行映像映射到进程用户空间并开始执行时,只有很少一部分虚拟页被装入了物理内存。在进程后续到执行过程中,如果需要访问到数据并不在物理内存中,则产生一个缺页中断(其实是异常),将所需页从交换区或磁盘中调入物理内存,这个过程即虚拟内存中到请页机制。

进程到虚存区

那么对于一个任意的进程,我们可以通过下面到方法查看其地址空间中到内存区域。

我们先看一个简单的测试程序:

#include < stdio.h >
#include < stdlib.h >

int main()
{
	int i=1;
	char *str=NULL;
	printf("hello,world!\n");
	str=(char *)malloc(sizeof(char)*1119);

	sleep(1000);

	return 0;
}

这个程序中使用到了malloc函数,因此str变量存储于堆中。我们通过打印/proc/3530/maps文件,即可看到该进程的内存空间划分。其中3530是该进程的id。

edsionte@edsionte-desktop:~$ cat /proc/3530/maps
0014a000-00165000 r-xp 00000000 08:07 398276     /lib/ld-2.11.1.so
00165000-00166000 r--p 0001a000 08:07 398276     /lib/ld-2.11.1.so
00166000-00167000 rw-p 0001b000 08:07 398276     /lib/ld-2.11.1.so
001d8000-0032b000 r-xp 00000000 08:07 421931     /lib/tls/i686/cmov/libc-2.11.1.so
0032b000-0032c000 ---p 00153000 08:07 421931     /lib/tls/i686/cmov/libc-2.11.1.so
0032c000-0032e000 r--p 00153000 08:07 421931     /lib/tls/i686/cmov/libc-2.11.1.so
0032e000-0032f000 rw-p 00155000 08:07 421931     /lib/tls/i686/cmov/libc-2.11.1.so
0032f000-00332000 rw-p 00000000 00:00 0
00441000-00442000 r-xp 00000000 00:00 0          [vdso]
08048000-08049000 r-xp 00000000 08:09 326401     /home/edsionte/test
08049000-0804a000 r--p 00000000 08:09 326401     /home/edsionte/test
0804a000-0804b000 rw-p 00001000 08:09 326401     /home/edsionte/test
08958000-08979000 rw-p 00000000 00:00 0          [heap]
b78ce000-b78cf000 rw-p 00000000 00:00 0
b78dd000-b78e0000 rw-p 00000000 00:00 0
bfa6a000-bfa7f000 rw-p 00000000 00:00 0          [stack]

每一行信息依次显示的内容为内存区域其实地址-终止地址,访问权限,偏移量,主设备号:次设备号,inode,文件。

上面的信息不但包含了test可执行对象的各内存区域,而且还分别显示了 /lib/ld-2.11.1.so(动态连接程序)文件和/lib/tls/i686/cmov/libc-2.11.1.so(C库)文件的内存区域信息。

我们从某个内存区域的访问权限上可以大致判断该区域的类型。各个属性符号的意义为:r-read,w-write,x-execute,s-shared,p-private。因此,r-x一般代表程序的代码段,即可读,可执行。rw-可能代表数据段,BSS段和堆栈段等,即可读,可写。堆栈段从行信息的文件名就可以区分;如果某行信息的文件名为空,那么可能是BSS段。另外,上述test进程共享了内核动态库,所以在00441000-00442000行处文件名显示为vdso(Virtual Dynamic Shared Object)。

mmap系统调用

通过mmap系统调用可以在进程到用户空间中创建一个新到虚存区。该系统调用到原型如下:

#include
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

该函数可以将以打开的文件映射到进程用户空间到一片内存区上,执行成功后,该函数返回这段映射区到首地址。用户得到这片虚存的首地址后,就可以像访问内存那样访问文件。

该系统调用的参数说明如下:

addr:映射到用户地址空间到起始地址;
length:映射区以字节为单位到长度;
prot:对映射区到访问模式。包括PROT_EXEC(可执行),PROT_READ (可读),PROT_WRITE(可写),PROT_NONE(文件不可访问)。这个访问模式不能超过所映射文件到打开模式。比如被映射的文件打开模式为只读,那么此处到访问模式不能是可读写的。
flags:这个字段比较灵活,不同到标志有不同的功能,具体如下:
MAP_SHARED:创建一个可被子进程共享的映射区;
MAP_PRIVATE:创建一个“写实复制”的映射区;
MAP_ANONYMOUS:创建一个匿名到映射区,该虚存区与进程无关;
fd:所要映射到进程用户空间的文件描述符,该文件必须为以打开的文件;
offset:文件的起始映射偏移量;

mmap()举例

在该程序中,首先以只读方式打开文件test.c,再通过该文件返回到文件描述符和mmap函数将test.c文件映射到当前进程到用户地址空间中。成功执行mmap函数后,buf被赋值为所映射的虚存区的首地址。注意,mmap函数返回的是void型指针,而buf是char型指针。将mmap返回值赋值给buf变量时,自动将void*转化为char*型。

最后,就像平常我们使用一个char型指针变量那样,依次打印出buf中到数据。

#include < stdio.h >
#include < sys/mman.h >
#include < fcntl.h >
int main()
{
	int i,fd;
	char *buf = NULL;

	fd = open("./test.c", O_RDONLY);
	if(fd < 0)
	{
		printf("open error\n");
		return -1;
	}

	buf = mmap(NULL, 12, PROT_READ, MAP_PRIVATE ,fd, 0);
	for(i = 0;i < 12;i++)
	{
		printf("%c",buf[i]);
	}
	printf("\n");

	return 0;
}

try一下!

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key