Datei-Header in einen Record lesen

21/04/2009 - 18:07 von Tim Ritberg | Report spam
Hi!

Ich habe mir einen Record gebaut der sieht so aus:

THeader = record
CRC : Word; // CRC of fields HEAD_TYPE to RESERVED2
H_TYPE : Byte; // Header type: 0x73
FLAGS : Word; // Bit flags
SIZE : Word; // header total size comments
RESERVED1 : Word;
RESERVED2 : LongWord;

Addiert ergibt das 13 Bytes. Einlesen kann ich so:
BlockRead(RarArchive, myheader, 13)

Aber es scheint nicht das gleiche zu sein wie:
var byteArray : array[1..13] of byte;

BlockRead(RarArchive, byteArray, 13);

Im Record scheinen die Byte durcheinander zu sein, jedenfalls nicht im
richtig Feld. Was ist denn da los?
Oder gibts einen besseren Weg einen Header einzulesen?
 

Lesen sie die antworten

#1 Sieghard Schicktanz
21/04/2009 - 20:31 | Warnen spam
Hallo Tim,

Du schriebst am Tue, 21 Apr 2009 18:07:54 +0200:

Ich habe mir einen Record gebaut der sieht so aus:

THeader = record
CRC : Word; // CRC of fields HEAD_TYPE to RESERVED2


2 Bytes *)

H_TYPE : Byte; // Header type: 0x73


1 Byte *)

FLAGS : Word; // Bit flags
SIZE : Word; // header total size comments


4 Bytes

RESERVED1 : Word;


2 Bytes *)

RESERVED2 : LongWord;


4 Bytes

Addiert ergibt das 13 Bytes.



2+ 1+ 4+ 2+ 4 - stimmt, auf den ersten Blick.

Addiert ergibt das 13 Bytes. Einlesen kann ich so:
BlockRead(RarArchive, myheader, 13)

Aber es scheint nicht das gleiche zu sein wie:
var byteArray : array[1..13] of byte;

BlockRead(RarArchive, byteArray, 13);



Doch, insofern Du damit genau 13 Bytes einliest.

Im Record scheinen die Byte durcheinander zu sein, jedenfalls nicht im
richtig Feld. Was ist denn da los?



Hier kommen die *) von oben 'rein: Bei 32-Bit-Maschinen sind die Zugriffe
auf solche "fehlausgerichteten" (missaligned) Daten oft langsam, es ginge
schneller, wenn alle Datenfelder auf wenigstens geraden oder besser, durch
4 teilbaren Adressen, sàßen. Deswegen füllen "viele" (eigentlich alle)
Compiler für solche Maschinen die Daten so auf, daß die Record-Felder an
zugriffsmàßig günstigen Positionen zu liegen kommen. Bei Deinem Record sàhe
eine àquvalente Deklaration wahrscheinlich so aus:

THeader = record
CRC : Word; // CRC of fields HEAD_TYPE to RESERVED2
H_TYPE : Byte; // Header type: 0x73
Filler_1: byte; ////<< legt nàchstes Feld auf Offset 4
FLAGS : Word; // Bit flags
SIZE : Word; // header total size comments
RESERVED1 : Word; ////<< dieses Feld liegt auf Offset 8
Filler_2: byte; ////<< legt nàchstes Feld auf Offset 12
RESERVED2 : LongWord; ////<< weil ein longword 4 Bytes hat

Damit hat der Record dann (mindestens) _16_ Bytes - Du kannst das ja mal
mit "WriteLn ('Recordgröße: ", SizeOf (THeader));" nachprüfen.

(BTW, beim Arbeiten mit Datenstrukturen auf "niedriger Ebene" ist es _immer_
zu empfehlen, _nicht_ mit festen Größenangaben zu arbeiten, sondern mit den
durch den "SizeOf"-Operator bestimmten Größen. Damit stellt man zum einen
sicher, daß man Zugriffe auf außerhalb liegende Variablen vermeiden kann,
zum zweiten, daß die richtige Anzahl Datenbytes bearbeitet wird, und
schließlich auch, daß bei Änderungen an der Datenstruktur nicht auf einmal
etwas ganz anderes bearbeitet wird als beabsichtigt. Außerdem kann man
damit auch feststellen, ob man wirklich die richtige Datengröße benutzt
oder seine Struktur noch hier und da anpassen muß.)

Oder gibts einen besseren Weg einen Header einzulesen?



Sicher - solche Verwicklungen hat sogar schon Niklaus Wirth bei der
originalen Definition von Pascal berücksichtigt, da gab's noch gar keine
PCs mit mehr als 8 Bit Speicherbreite... ;-)

Da gibt's ein Schlüsselwort "PACKED", das die Speicherbelegung von Records
und Arrays (!) so modifiziert, daß diese den miniml möglichen Platz belegen.
Damit kannst Du Deinen Compiler anweisen, _kein_ "Alignment" (d.h. keine
Adressausrichtung der Felder) zu machen, und damit wird der Record dann
wirklich nur so groß wie die enthaltenen Daten verlangen.

Wàhrend "PACKED" von allen Pascal-Compilern verstanden werden muß (und sie
das tunlichst auch beachten sollten), gibt es aber auch ein paar andere
Möglichkeiten, solche Modifikationen vorzunehmen, die allerdings dann
Compiler-spezifisch sind: das sind die Compiler-Optionen oder -Schalter
oder "Pragmas" oder wie die bei einem Compiler auch immer genannt werden
mögen.

Bei TP/BP und Delphi (Borland u.s.w.) sowie bei FPC (Free Pascal) ist für
Deinen Fall zustàndig:

$A[+/-] bzw. $ALIGN[ON/OFF] Data alignment

Bitte schau' Dir mal die Dokumentation zu Deinem speziellen Compiler
daraufhin (und auch ganz allgemein) genauer an!

(Weitergabe von Adressdaten, Telefonnummern u.à. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder àhnlichem)
Mit freundlichen Grüßen, S. Schicktanz

Ähnliche fragen