Struct alignment

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Struct alignment

Beitrag von RazorX »

Servus,
ich schreibe gerade einen Parser für das Zip Dateiformat, funktioniert soweit auch super, dennoch werd ich bezüglich des struct alignments wahnsinnig. Gestern dachte ich ich hätte das Problem durch __declspec(align(1)) in den Griff bekommen, heute bekomme ich schon wieder Probleme:

Code: Alles auswählen

namespace zip {
	struct __declspec(align(1)) local_file_header {
		FATE_UTIL_API static const int32_t SIGNATURE;

		int32_t		signature;
		int16_t		minVersion;
		int16_t		generalPurpose;
		int16_t		compressionMode;
		int16_t		fileLastModificationTime;
		int16_t		fileLastModificationDate;
		int32_t		crc32;
		int32_t		compressedSize;
		int32_t		uncompressedSize;
		int16_t		fileNameLength;
		int16_t		extraFieldLength;
		std::string	fileName;
		std::string	extraField;
	};
};

// ...

archiveStream->seekg(localOffset, std::istream::beg);
archiveStream->read(reinterpret_cast<char*>(&fileInfo.localHeader.signature), 4);

if(fileInfo.localHeader.signature != zip::local_file_header::SIGNATURE) {
	throw std::ios_base::failure("...");
}

// Funktioniert
archiveStream->read(reinterpret_cast<char*>(&fileInfo.localHeader.minVersion), 10);
archiveStream->read(reinterpret_cast<char*>(&fileInfo.localHeader.crc32), 12);
archiveStream->read(reinterpret_cast<char*>(&fileInfo.localHeader.fileNameLength), 4);

// Funktioniert nicht
archiveStream->read(reinterpret_cast<char*>(&fileInfo.localHeader.minVersion), 26);
Defacto werden mir dann Bytes so verschoben, dass der Wert aus fileNameLength 0 wird und uncompressedSize einen magischen Wert bekommt. Kann mir bitte mal jemand erklären warum mir der Compiler das Layout verändert? (Ich hoffe ja mal nicht das es an der VS2012 Nov CTP liegt)

Mit freundlichem Gruß
RazorX
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Struct alignment

Beitrag von CodingCat »

Dein Problem ist nicht das Alignment, sondern das Packing. __declspec(align(1)) legt fest, dass Instanzen der Struktur bei Stackallokation an jeder beliebigen Adresse beginnen dürfen (also gar kein Alignment erfordern). Was du suchst, ist #pragma pack(1) struct ..., um das Padding/Alignment innerhalb der Struktur zu beeinflussen bzw. auszuschalten.

Außerdem: Willst du in dieser Struktur wirklich std::strings haben? Auch wenn du sie aus dem Read per Read-Länge rausnimmst, erscheinen sie in dieser Struktur unangebracht.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: Struct alignment

Beitrag von RazorX »

Danke, funktioniert super!

@std::strings: Hast schon Recht, denke mal da machen std::unique_ptr<const char*> mehr Sinn. Geht mir auch ein bisschen um den Komfort nicht überall aufräumen zu müssen wenn ich das Archiv wegwerfe.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Struct alignment

Beitrag von CodingCat »

RazorX hat geschrieben:@std::strings: Hast schon Recht, denke mal da machen std::unique_ptr<const char*> mehr Sinn. Geht mir auch ein bisschen um den Komfort nicht überall aufräumen zu müssen wenn ich das Archiv wegwerfe.
Nein, so war das nicht gemeint. Es spricht grundsätzlich nichts gegen einen std::string, um Strings zu speichern. Dieser sollte nur nicht in einer binär gelesenen Struktur auftauchen, weil std::strings ganz sicher niemals per Bitmuster serialisierbar/lesbar sind. Besser wäre hier, die Struktur in einen binär lesbaren und einen nicht binär lesbaren Teil aufzuteilen, z.B. so:

Code: Alles auswählen

#pragma pack(1)
struct binary_local_file_header {
                FATE_UTIL_API static const int32_t SIGNATURE;

                int32_t         signature;
                int16_t         minVersion;
                int16_t         generalPurpose;
                int16_t         compressionMode;
                int16_t         fileLastModificationTime;
                int16_t         fileLastModificationDate;
                int32_t         crc32;
                int32_t         compressedSize;
                int32_t         uncompressedSize;
                int16_t         fileNameLength;
                int16_t         extraFieldLength;
};
struct local_file_header {
                binary_local_file_header  binary;
                std::string               fileName;
                std::string               extraField;
};
Damit kannst du obigen Code zusammenschrumpfen zu folgendem:

Code: Alles auswählen

archiveStream->seekg(localOffset, std::istream::beg);
archiveStream->read(reinterpret_cast<char*>(&fileInfo.localHeader.binary), sizeof(fileInfo.localHeader.binary));

if(fileInfo.localHeader.binary.signature != zip::binary_local_file_header::SIGNATURE) {
        throw std::ios_base::failure("...");
}
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Antworten