在C中使用mmap读取二进制文件时的Segfault

时间:2012-04-15 17:30:35

标签: c binaryfiles mmap

我正在尝试在C中使用mmap,看看它是如何工作的。目前我尝试使用mmap逐字节读取二进制文件。我的代码是这样的:

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

int main(int argc, char *argv[]) {
    int fd;
    char *data;

    for ( int i = 1; i<argc; i++)
    {

        if(strcmp(argv[i],"-i")==0)
            fd = open(argv[i+1],O_RDONLY);
    }

    data = mmap(NULL, 4000, PROT_READ, MAP_SHARED, fd, 8000);
    int i = 0;
    notation = data [i];
    // ......

}

当我尝试使用notation = data [0]并出现段错误时,会出现问题。我确信二进制文件中的第一个字节也是一个字符。我的for循环检查编译时是否有-i标志,如果有下一个参数应该是文件名。

1 个答案:

答案 0 :(得分:4)

似乎mmap失败,因为偏移量不是页面大小的倍数。您可以使用perror测试它,并查看问题是无效的参数。如果你写:

data = mmap(NULL, 4000, PROT_READ, MAP_SHARED, fd, 8000);
perror("Error");

至少在我的OS X上打印出以下错误:

错误:参数无效

将偏移量从8000更改为4096或8192。 6144没有,所以它必须是这个平台上的4096的倍数。顺便说一下,

printf("%d\n",getpagesize());

打印4096.您应该将偏移量向下舍入到mmap的最接近的倍数,并在访问该区域时将余数添加到i。当然,从该功能获取特定平台的页面大小。它可能是在你已经声明的unistd.h中定义的。

以下是如何正确处理偏移并处理可能的错误。它在位置8000打印字节:

int offset = 8000;
int pageoffset = offset % getpagesize();

data = mmap(NULL, 4000 + pageoffset, PROT_READ, MAP_SHARED, fd, offset - pageoffset);
if ( data == MAP_FAILED ) {
    perror ( "mmap" );
    exit ( EXIT_FAILURE );
}
i = 0;
printf("%c\n",data [i + pageoffset]);