mikrocontroller.net

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


Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey,

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.

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

Autor: grmbrl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

das habe ich vergessen zu erwähnen... Ich gehe von Little-Endian aus ;)
Architektur ist x86 mit Linux als OS.
Ein Beispiel:
uint32_t size = 12345678; // 0xbc614e
uint16_t offset = 5000; // 0x1388
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 ;)

Autor: Nico22 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
johannes schrieb:

>
> uint32_t size = 12345678; // 0xbc614e
> uint16_t offset = 5000; // 0x1388
> 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

Einspruch, Euer Ehren.

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

Autor: Imon (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :
struct header
{
   uint32_t size;
   uint16_t offset;
   char name[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,

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mal deine struct genommen und mir unter Linux mit
gcc 4.3 davon sizeof ausgeben lassen.
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>

struct header
{
   uint32_t size;
   uint16_t offset;
   char name[6];
};

int main( int nargs, char **args )
{
  printf( "%d\n", sizeof(struct header) );
  return 0;
}


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.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
struct header2
{
   char name[6];
   uint32_t size;
   uint16_t offset;
};

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

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
int16_t a[4];
int16_t *p;

p = a;

if(*(p + 2) == a[2]) //<- Ist immer true

Matthias

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.