2016-03-24 2 views
0

Könnten Sie bitte erklären, warum mein Programm seltsame Werte aus einer Datei liest? Ich versuche eine Datei mit mmap zu lesen. Der Grund, warum ich diese Funktion verwende, ist zu verstehen, wie es funktioniert. Dann würde ich es mit/dev/mem verwenden, um binäre Daten an bestimmten physikalischen Speicheradressen zu lesen.Lesen einer Binärdatei mit mmap()

Ich habe eine Datei 'Hallo1.raw' mit dem folgenden Python-Skript erstellt.

Dann habe ich versucht, es mit dem c-Programm unten zu lesen.

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

int main(){ 

int fd = open("hello1.raw",O_RDWR); 

struct stat st; 
fstat(fd, &st); 
size_t size=st.st_size; 

int * a = mmap(0, size, PROT_READ|PROT_EXEC ,MAP_SHARED , fd, 0); 
printf("address of hello1.raw: %p\n",a); 
printf("data in hello1.raw: %d\n", *a); 

int b = munmap(a, size); 
close(fd); 

return 0; 
} 

Aber dieses Programm druckt seltsamen Wert.

address of hello.raw: 0x10238d000 
data in hello.raw: 12592 

Die Daten sind nicht 01, sondern 12592.

+0

'd.write (b'01 ')' was soll das heißen? eine Charakterkonstante? 'write()' erwartet drei Argumente, ein int für den Dateideskriptor, einen Puffer (oder Zeiger) für die Daten und einen int für die Größe. (Ok, es ist Python). Verwenden Sie od -CX oder hexdump, um den tatsächlichen Inhalt zu sehen. BTW: mmap() funktioniert auf Speicherseiten. Sie sollten nichts außer dem physischen EOF annehmen. – joop

+0

@joop Vielen Dank für Ihre Antwort. Bedeutet das, dass die von mir erstellte Datei hello1.raw keinen binären Wert 01 enthält? – SD11

+0

Wie gesagt: Verwenden Sie hexdump oder od -X, um den Inhalt zu überprüfen. Und benutze ls, um seine Größe und seinen Modus zu überprüfen. – joop

Antwort

1
#include <stdio.h> 
#include <sys/stat.h> 

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

int main(){ 

int fd, rc , ii; 
int *ptr; 
struct stat st; 
size_t size; 

fd = open("hello1.raw", O_RDWR); 

rc = fstat(fd, &st); 
fprintf(stderr, "stat() = %d\n", rc); 
size=st.st_size; 
fprintf(stderr, "size=%zu\n", size); 

ptr = mmap(0, size, PROT_READ|PROT_EXEC ,MAP_SHARED , fd, 0); 
fprintf(stderr, "address of hello1.raw: %p\n", ptr); 

for (ii=0; ii < size/sizeof *ptr; ii++) { 
    printf("data in raw[%d]: %d\n", ii, ptr[ii]); 
     } 

rc = munmap(ptr, size); 
fprintf(stderr, "unmap() = %d\n", rc); 
close(fd); 

return 0; 
} 

  • Zunächst einmal: die Rückgabewerte für Systemaufrufe überprüfen und zu stderr melden.
  • Zweitens: mmap() arbeitet mit Seiten. Wenn st.st_size kein Vielfaches der Seitengröße ist, wird es aufgerundet. (Linux füllt den Rest mit Nullen)
  • Testen Sie dies, indem Sie "OMG \ n" in die hello1.raw-Datei (4 Bytes) setzen und das Programm ausführen.
  • Entfernen Sie jetzt ein Zeichen) zB - >> "OM \ n") Beenden Sie das Programm erneut.

1:

$ ./a.out 
stat() = 0 
size=4 
address of hello1.raw: 0xa64000 
data in raw[0]: 172445007 
unmap() = 0 

2:

$ ./a.out 
stat() = 0 
size=3 
address of hello1.raw: 0xe37000 
unmap() = 0 

Erläuterung: im ersten Durchlauf die Datei hat size = 4, die Mmap erfolgreich ist, und Der Int wird gedruckt. (sizeof int ist 4). Im zweiten Fall ist mmap erfolgreich, aber der Int wird nicht gedruckt (meine Version der Schleife weigert sich, auf MMAPapped Speicher jenseits des eof zu verweisen), wenn Sie erlauben Referenzen über eof der oberen Bytes (unter der Annahme Big Endian hier) der int-Wert würde als Null angezeigt, da das System die Seite mit Null aufgefüllt hat.

Wenn Sie den Effekt der Null-Auffüllung sehen möchten, ändern Sie die for-Schleife zu for (ii=0; ii <= size/sizeof *ptr; ii++) { und wiederholen Sie das obige Experiment.