Forum: Compiler & IDEs Datei lesen und Werte in Struct übernehmen


von johannes (Gast)


Lesenswert?

Hey,

ich habe folgende struct:
1
struct header
2
{
3
   uint32_t size;
4
   uint16_t offset;
5
   char name[6];
6
};

Und eine Datei, die genau so formatiert ist wie die struct header.

Wie kann ich nun am Besten die 12 Byte aus der Datei lesen und die Werte 
in die Struct übernehmen?
Ich steh arbeite gerade das erste mal mit Strukturen..

Würde mich freuen wenn mir da jemand einen Tipp geben kann ;)

ciao
johannes

von grmbrl (Gast)


Lesenswert?

Guck dir mal fread und fwrite an. Imho darf der Compiler allerdings 
Padding-Bytes in die Struktur packen, dann wird das u.U. nichts.

von Hc Z. (mizch)


Lesenswert?

Die Frage ist nicht so einfach, wie sie zunächst aussieht.  Denn es gibt 
so allgemein keine
> Datei, die genau so formatiert ist wie die struct header.

„So allgemein keine“, weil mit „so formatiert wie“ Dinge nicht 
spezifiziert sind wie Byte Order (ist das Byte auf der niedrigsten 
Adresse das Byte mit der höchsten Wertigkeit?  Bei x86 und AVR: nein, 
wenn die Bytes vom Netz kamen oder der 68xx(x)/Coldfire-Familie: ja). 
Du musst also das Layout genauer spezifizieren, ebenso (wegen Padding) 
die Quell- und Zielarchitektur samt Compiler und dessen Optionen und 
davon abhängig dann konvertieren.

Du sagst also am besten ein konkretes Beispiel, an dem entlang sich eine 
Lösung überlegen lässt.

Für etwas allgemeinere Lösungen gibt es dann noch htons(), ntohs() usw. 
Diese lösen compilerübergreifend das Problem der Byte Order, nicht aber 
des Paddings.  Zudem musst Du jedes struct-Element einzeln 
durchschicken.

von johannes (Gast)


Lesenswert?

Hallo,

das habe ich vergessen zu erwähnen... Ich gehe von Little-Endian aus ;)
Architektur ist x86 mit Linux als OS.
Ein Beispiel:
1
uint32_t size = 12345678; // 0xbc614e
2
uint16_t offset = 5000; // 0x1388
3
char name[6]; // "test  " -> 0x74 0x65 0x73 0x74 0x20 0x20

Also sieht der Hexdump der Datei folgendermaßen aus:
00 4e 61 bc 88 13 74 65 73 74 20 20

Und das möchte ich nun so in die Struct einlesen..

Ich hab gedacht dafür gibt es vllt eine einfache Möglichkeit..

viele grüße ;)

von Nico22 (Gast)


Lesenswert?

Benötigte Includes musst du dir selber suchen ;-)

struct header
{
   uint32_t size;
   uint16_t offset;
   char name[6];
} __attribute__((_packed_));

int main() {
    int file = open("datei.txt", O_RDONLY);
    struct header head;

    read(file, &head, sizeof(head));

    /* Eventuell Nullbyte zur Sicherheit einfügen: */
    head.name[5] = 0;

    close(file);

    printf("Name: %s\n", head.name);
    return 0;
}

von Hc Z. (mizch)


Lesenswert?

johannes schrieb:

>
1
> uint32_t size = 12345678; // 0xbc614e
2
> uint16_t offset = 5000; // 0x1388
3
> char name[6]; // "test  " -> 0x74 0x65 0x73 0x74 0x20 0x20
4
>
>
> Also sieht der Hexdump der Datei folgendermaßen aus:
> 00 4e 61 bc 88 13 74 65 73 74 20 20

Einspruch, Euer Ehren.

4e 61 bc 00 88 13 74 65 73 74 20 20

von Imon (Gast)


Lesenswert?

johannes schrieb:
> ich habe folgende struct:struct header
> {
>    uint32_t size;
>    uint16_t offset;
>    char name[6];
> };
>
> Und eine Datei, die genau so formatiert ist wie die struct header.

Sicher? beim PC würde ich fast wetten das zwischen offset und name 2 
Padding Bytes eingeschoben werden. Ausserdem hat der PC eine Little 
endian Darstellung. Das ist auch nicht unbedingt das was man tippen 
würde wenn man die Datei Manuell Bearbeitet. Spezifizier doch mal die 
Datei und das System auf denn du Arbeitest. Dann können wir dir sicher 
besser Helfen,
Intressant ist zum beispiel wie die Formatierungs in der datei sind

fälle wie size =31 ,offset =2  steht das nun als 312 in der Datei oder 
als
31 2 oder 31\n 2\n und wenn da 312 steht,wie unterscheidest du das nun 
von size 3 offset 12 ( Ich weiß das das unlogisch ist! aber dein 
Programm ggf. nicht.)

generell hilft es wahrscheinlich für eine Quick and Dirty lösung den 
Kompiler zu sagen das man die struct packet haben will und die Zahlen 
mit führenden Nullen zu speichern, und die fehlenden Buchstaben des 
Namens mit '\0' zu füllen.

beim gcc geht das gepackt so :
1
struct header
2
{
3
   uint32_t size;
4
   uint16_t offset;
5
   char name[6];
6
} __attribute__((packed)) ;

das könnte man wahrscheinlich mit denn Führenden Nullen bei den Zahlen 
und den '\0' bei den Name einfach so in den Speicher Der Struktur 
Kopieren. Gegeben falls müssen noch die Endianess beachtet und 
umgemodelt werden,

von Klaus W. (mfgkw)


Lesenswert?

Ich habe mal deine struct genommen und mir unter Linux mit
gcc 4.3 davon sizeof ausgeben lassen.
1
#include <stdlib.h>
2
#include <stddef.h>
3
#include <stdio.h>
4
#include <stdint.h>
5
6
struct header
7
{
8
   uint32_t size;
9
   uint16_t offset;
10
   char name[6];
11
};
12
13
int main( int nargs, char **args )
14
{
15
  printf( "%d\n", sizeof(struct header) );
16
  return 0;
17
}


Ergebnis: 12 Byte

D.h., daß du in diesem einen Fall die Warnungen in den Wind
schlagen kannst und einfach mit fread aus der Datei in die struct
lesen kannst.

von Hc Z. (mizch)


Lesenswert?

Das

__attribute__((packed));


würde ich drin lassen, um vorzubeugen, dass es mit einem späteren 
gcc-Compiler auch geht.  Tut ja nicht weh.  In ein paar Jahren haben wir 
vielleicht 64-Bit- oder (von mir aus) auch 256-Bit-Alignments.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

Hc Zimmerer schrieb:
> Das
>
> __attribute__((packed));
>
> würde ich drin lassen, um vorzubeugen, dass es mit einem späteren
> gcc-Compiler auch geht.  Tut ja nicht weh.  In ein paar Jahren haben wir
> vielleicht 64-Bit- oder (von mir aus) auch 256-Bit-Alignments.

Es gibt bei genau dieser Struktur für den Compiler eigentlich keinen 
Grund Padding Bytes einzufügen. Jedes Element kommt auch ohne Padding 
auf passende Offsets.

Bei
1
struct header2
2
{
3
   char name[6];
4
   uint32_t size;
5
   uint16_t offset;
6
};

sieht das aber schon ganz anders aus. __attribute__((packed)) kann 
einen aber auch mal ärgern wenn man auf Maschinen unterwegs ist die gar 
keine "ungeraden" Zugriffe erlauben (z.B. ARM9, MIPS)

Matthias

von Hc Z. (mizch)


Lesenswert?

Μαtthias W. schrieb:
> Es gibt bei genau dieser Struktur für den Compiler eigentlich keinen
> Grund Padding Bytes einzufügen.

Derzeit.  Du gehst von dem aus, was heute üblich ist.  Schon ein 
32-Bit-Alignment würde nicht mehr passen, und das gibt es schon.  Nicht 
umsonst sprach ich von zukünftigen Veränderungen und (als willkürliches 
Beispiel) 64/256-bit-Alignments.

> __attribute__((packed)) kann einen aber auch mal ärgern

Spätestens dann war's mit dieser Methode Essig.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hc Zimmerer schrieb:
> Μαtthias W. schrieb:
>> Es gibt bei genau dieser Struktur für den Compiler eigentlich keinen
>> Grund Padding Bytes einzufügen.
>
> Derzeit.  Du gehst von dem aus, was heute üblich ist.  Schon ein

Nö. Eher von technischen Gegebenheiten.

> 32-Bit-Alignment würde nicht mehr passen, und das gibt es schon.  Nicht

???

> umsonst sprach ich von zukünftigen Veränderungen und (als willkürliches
> Beispiel) 64/256-bit-Alignments.

Warum sollte ein 16 Bit Datentyp mehr als 2 Byte Alignment benötigen? 
Und wie realisiert man in diesem Fall ein uint16_t arr[16];? Padding 
zwischen jedem Element? IIRC ist das laut C Standard garnicht möglich da
1
int16_t a[4];
2
int16_t *p;
3
4
p = a;
5
6
if(*(p + 2) == a[2]) //<- Ist immer true

Matthias

von Hc Z. (mizch)


Lesenswert?

Du wirfst arrays, Pointerarithmetik und structs zusammen und rührst um. 
Dann soll eine Pointerarithmetik dafür herhalten, dass eine struct nicht 
auf 32 Bits gepaddet wird.  Das scheint mir wenig sinnvoll.

Warum auf 32 Bits gepaddet werden soll?  Weil in einem 32 Bit breiten 
Speicher ein 32-Bit-Zugriff auf eine modulo-4-Adresse (Bit 1 und Bit 0 
auf 0) in einem Zugriff zu erledigen ist, auf einer Adresse mit 
gesetztem Bit 1 aber 2 Zugriffe benötigt.

Und lass mir bitte Arrays raus, wenn es um das Padding von structs geht. 
Die haben nichts miteinander zu tun.  Ich möchte es auch insgesamt dabei 
bewenden lassen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.