函數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 //匿名映射,映射區不與任何文件關聯。)的別稱,不再被使用。因為我們創建一個匿名映射,所以我們不需要傳遞文件描述符。