我有这个程序应该以读写模式映射文件并能够编辑其内容。此外,这是为大约 40-50 GB 编写的文件,因此我需要 mmap64
。问题是,虽然 mmap64
没有返回错误,但它返回的地址不可访问。
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>
typedef unsigned long long u64;
void access_test(u64 p, u64 sz)
{
u64 i;
char tmp;
for (i=0; i<sz; i++) {
tmp = *(char*)(p+i);
}
}
int main(int argc, char *argv[])
{
int fd;
long long int sz, p;
struct stat buf;
fd = open(argv[1], O_RDWR, 0x0666);
if (fd == -1) {
perror("open");
return 1;
}
fstat64(fd, &buf);
sz = buf.st_size;
printf("File size: 0x%016llx\n", sz);
p = mmap64 (0, buf.st_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
if (p == -1) {
perror ("mmap");
return 1;
}
access_test(p,sz);
if (close (fd) == -1) {
perror ("close");
return 1;
}
if (munmap ((void*)p, buf.st_size) == -1) {
perror ("munmap");
return 1;
}
return 0;
}
结果是一个小文件:
$ ./testmmap minicom.log
File size: 0x0000000000000023
[1] 8282 segmentation fault (core dumped) ./testmmap minicom.log
大的也是一样。
最佳答案
编译时始终启用警告
这是启用警告后的结果:
$ gcc mmp.c -Wall -g
mmp.c: In function ‘access_test’:
mmp.c:18:10: warning: variable ‘tmp’ set but not used [-Wunused-but-set-variable]
char tmp;
^
mmp.c: In function ‘main’:
mmp.c:36:5: warning: implicit declaration of function ‘fstat64’ [-Wimplicit-function-declaration]
fstat64(fd, &buf);
^
mmp.c:40:5: warning: implicit declaration of function ‘mmap64’ [-Wimplicit-function-declaration]
p = mmap64 (0, buf.st_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
这里的最后两个警告非常重要。他们说mmap64没有原型(prototype)。因此,C 为您提供了一个默认原型(prototype),但它是错误的,至少对于 mmap64() 调用而言(因为原型(prototype)将返回一个 int,它不能表示 64 位 Linux 主机上的指针)
fstat64() 的参数也是一个 struct stat64
顺便说一句,这是另一个问题。
使特定的 64 位功能可用
如果要使fstat64()/mmap64()
函数可用,您需要使用_LARGEFILE 和LARGEFILE64_SOURCE #define 编译代码,参见信息here , 所以你应该将其编译为例如:
gcc -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE mmp.c -Wall -g
或者使用#define _FILE_OFFSET_BITS=64
但是没有必要这样做。编译时调用普通的fstat()
和mmap()
和#define _FILE_OFFSET_BITS=64
即可。例如:
gcc -D_FILE_OFFSET_BITS=64 mmp.c -Wall -g
这将启用对大文件的支持,例如如果需要(例如,如果您在 32 位主机上),将 mmap() 调用转换为 mmap64()。
如果您尝试 mmap() 一个 50 GB 的文件,您无论如何都需要在 64 位主机上,而在 64 位 Linux 主机上则不需要任何这些 - mmap() 和 fstat( ) 无需执行任何操作即可处理大型文件。
使用指针
下一个问题是您要将 mmap()
的返回值分配给一个整数。这可能碰巧有效,但代码确实因此看起来很奇怪。如果您想将事物视为 char *
,请将其分配给 char *
。不要把指针强制转换为 64 位整数类型。
例如你的访问函数应该是:
void access_test(char *p, u64 sz)
{
u64 i;
char tmp;
for (i=0; i<sz; i++) {
tmp = p[i];
}
}
和p
应该在main()中声明为char *p;
,或者如果你打算处理的话使用uint8_t *p;
数据作为二进制数据。
关于c - mmap 文件返回指向内存中不可访问位置的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20750066/