Я пытаюсь прочитать файл в строке с помощью 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. Что я делаю неправильно?
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
Нам не нравятся addr
, length
или offset
(например, они слишком большие или не выровнены на границе страницы). length
EINVAL
(начиная с Linux 2.6.12) length
0. flags
EINVAL
содержали ни MAP_PRIVATE
ни MAP_SHARED
, ни Ошибка -EINVAL
вызвана флагами, которые не могут быть MAP_PRIVATE
0. MAP_PRIVATE
MAP_SHARED
MAP_PRIVATE
или MAP_SHARED
. Я смог заставить его работать, используя MAP_PRIVATE
в Linux, x86-64.
Итак, вы должны добавить MAP_PRIVATE в mmap()
:
#include #include #include #include #include #include #include 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);