Ganze Struct auf einmal einlesen.
-
Also, ich habe ein Problem. Ich will eine struct mit fester Länge aus einer Datei lesen aber es klappt nicht. Die ersten eingelesenen Variablen sind noch richtig, aber aA ist definitiv falsch. Sie sollte 7 sein ist aber 0. Wenn ich in ein char-Array lese und an dieser Stelle extrahiere bekomme ich meine 7. Warum ist das so?
struct Header { unsigned int a1:32; unsigned int a2:16; unsigned int a3:16; unsigned int a4:16; unsigned int a5:16; unsigned int a6:16; unsigned int a7:32; unsigned int a8:32; unsigned int a9:32; unsigned int aA:16; unsigned int aB:16; }; // in main ifstream input("C:\\Test.dat", ios::in | ios::binary); if(input.is_open()) { Header header; input.read(reinterpret_cast<char*>(&header), 30); // Die 30 habe ich fest codiert, weil die Länge statisch ist // und sizeof(Header) 32 liefert wodurch ich in der Datei verrutschen würde }
Woran könnte das liegen? Liegen die Variablen nicht in der Reihenfolge im SPeicher wie im Code der struct? Habe in den FAQ nachgeschaut und da macht HumeSikkins das ähnlich
.
-
das Problem sind die Padding Bytes, dein Compiler vergrößert die Struktur so, dass du möglichst schnell auf die einzelnen Elemente zugreifen kannst. Du musst das padding deaktivieren.
(Aber speicher am besten nie Strukturen Binär, dann sparst du dir solche Probleme)
-
Also muss ich Element für Element auslesen?
-
Im MSVC kannst du das einfach unter Projekt -> Einstellungen -> Code -> C/C++ -> Code-Generation -> Struct-Element-Ausrichtung einstellen. Auf 1 Byte in diesem Fall.
Somit ist sizeof(Header) schon richtig. Standard ist nämlich 8 Byte. Bei 30 ergibts das 32.
Also entweder sizeof(header) nehmen (case sensitive hier nicht übersehen - ist besser mit Objekt statt mit Klasse) oder kingruedis Ratschlag befolgen ;).
MfG SideWinder
-
Am besten du befragst mal deine Compilerhilfe, wie du "packed structs" hinkriegst.
-
Mit #pragma pack kann man die große der Padding bytes bei manchen compilern beeinflussen.
-
Du solltest das Padding nur gezielt für die Strukturen aussschalten die es benötigen (z. B. zum binaeren FileIo, dort auch sinnvoll um Platz auf der Platte zu sparen. Außerdem Paddingbytes werden normalerweise nicht initialisiert, d.h. das Programm zweimal mit denselben Eingangsdaten gestartet ergibt 2 Files, diese Files sind identisch im Inhalt können sich aber in den Inhalten der Paddingbytes unterscheiden, somit sind bei einem CRC über das Daten oder einem binären Vergleich trotz inhaltlicher Gleichheit unterschiedlich).
Das Alignment (hier Synonym für Padding) auf eins zu setzen heißt dem Processor durch unnötige Arbeit zu bremsen, deshalb sollte man bei programminternen Strukturen (x86) das Alignment auf 4 oder 8 setzen.
Bekanntlichermaßen ist bei einer 32 Bit Maschine ein 32 Bit zugriff schneller als zwei 16 Bit Zugriffe und noch schnaller als 4 8Bit Zugriffe. folgende Situation.
#pragma packed struct eins { unsigned char a[3]; long int b; }; struct zwei { unsigned char a[2]; long int b; }; //jetzt unpacked struct drei { unsigned char a[3]; //---------hier fügt der Compiler ein Byte ein um die long int auf einer 32 Bit Boundary zu haben long int b; };
in struct eins muß der Processor die Variable b mit 4 8 Bitzugriffen holen
in struct zwei muß der Processor die Variable b mit 2 16 Bitzugriffen holen
in struct drei holt der Processor die Variable b mit 1 32 Bit Zugriff.je umfangreicher die Konstrukte mit solchen gepackten Strukturen (Felder,...) und je häufiger darauf zugegriffen wird desto geringer ist die Performance.