2013-12-08 35 views
4

我想讀取文件到一個字符串使用mmap。讀取一個文件到與mmap的字符串

我下面這個例子:http://www.lemoda.net/c/mmap-example/index.html

我的代碼看起來像這樣

unsigned char *f; 
int size; 
int main(int argc, char const *argv[]) 
{ 
    struct stat s; 
    const char * file_name = argv[1]; 
    int fd = open (argv[1], O_RDONLY); 

    /* Get the size of the file. */ 
    int status = fstat (fd, & s); 
    size = s.st_size; 

    f = (char *) mmap (0, size, PROT_READ, 0, fd, 0); 
    for (i = 0; i < size; i++) { 
     char c; 

     c = f[i]; 
     putchar(c); 
    } 

    return 0; 
} 

但訪問F [I]時,我總是收到一個segemation故障。 我在做什麼錯?

+5

你不檢查open'和'mmap'的'的返回值。如果你這樣做會怎樣? – usr2564301

回答

11

strace是你的朋友在這裏:

$ strace ./mmap-example mmap-example.c

... 
... (lots of output) 
... 
open("mmap-example.c", O_RDONLY)  = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=582, ...}) = 0 
mmap(NULL, 582, PROT_READ, MAP_FILE, 3, 0) = -1 EINVAL (Invalid argument) 
--- SIGSEGV (Segmentation fault) @ 0 (0) --- 
+++ killed by SIGSEGV +++ 

mmap手冊頁告訴你所有你需要知道;)

  • EINVAL我們不喜歡addrlength ,或offset(例如,他們太 大,或不等在頁面邊界上進行簽名)。
  • EINVAL(因爲Linux 2.6.12)length是0
  • EINVALflags既不含有MAP_PRIVATEMAP_SHARED,或
    包含這兩個值。

-EINVAL該錯誤是由標記,它們不能爲0要麼MAP_PRIVATEMAP_SHARED具有要被拾取而引起的。我已經能夠在Linux,x86-64上使用MAP_PRIVATE進行工作。

所以,你只需MAP_PRIVATE添加到mmap()

#include <stdio.h> 
#include <fcntl.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <sys/io.h> 
#include <sys/mman.h> 

int main(int argc, char const *argv[]) 
{ 
    unsigned char *f; 
    int size; 
    struct stat s; 
    const char * file_name = argv[1]; 
    int fd = open (argv[1], O_RDONLY); 

    /* Get the size of the file. */ 
    int status = fstat (fd, & s); 
    size = s.st_size; 

    f = (char *) mmap (0, size, PROT_READ, MAP_PRIVATE, fd, 0); 
    for (int i = 0; i < size; i++) { 
     char c; 

     c = f[i]; 
     putchar(c); 
    } 

    return 0; 
} 

注:我的第一個答案都包括了EINVAL另一個可能的原因:

size必須是整數系統頁面大小的倍數。到 獲取頁面大小使用功能getpagesize()

這實際上是不需要,但你必須考慮到,無論哪種方式,映射將始終在系統頁面大小的倍數進行考慮,所以,如果你想計算多少內存實際上是如何通過返回的指針已面市,更新size因爲這樣:

int pagesize = getpagesize(); 
size = s.st_size; 
size += pagesize-(size%pagesize); 
+0

甚至只是一個普通的調試器會告訴你'f'在崩潰的行上是'NULL',意味着對'mmap'的調用失敗。 –

+1

'size'不一定是頁面大小的倍數;我認爲OP的問題是需要指定'MAP_SHARED'的MAP_PRIVATE'。來自http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap。html:「實現在整個頁面上執行映射操作,因此,雖然參數len不需要滿足大小或對齊約束,但是實現將在任何映射操作中包含由範圍'[pa,pa + LEN)'。」 –

+0

你是對的:我誤讀了關於必須與頁面邊界對齊的信息。這就是mmap的man頁面所說的: EINVAL我們不喜歡addr,長度或偏移量(例如,它們太大或者不在頁面邊界上對齊)。 EINVAL(自Linux 2.6.12起)長度爲0. EINVAL **標誌既不包含MAP_PRIVATE或MAP_SHARED **,也不包含這兩個值。 我會更新答案:) –

相關問題