
Baruch
Wenn ich eine habe struct
Gibt es in C++ keine Möglichkeit, es sicher in eine Datei zu lesen/schreiben, die plattformübergreifend/Compiler-kompatibel ist?
Denn wenn ich das richtig verstehe, ‘polstert’ jeder Compiler je nach Zielplattform unterschiedlich.

Nawaz
Nein. Das ist nicht möglich. Es ist wegen fehlende Standardisierung von C++ auf Binärebene.
Don-Box schreibt (zitiert aus seinem Buch Essential COM, Kapitel COM als besseres C++)
C++ und Portabilität
Ist die Entscheidung getroffen, eine C++-Klasse als DLL zu verteilen, steht man vor einer der die grundlegenden Schwächen von C++das ist, Mangel an Standardisierung auf der binären Ebene. Obwohl das ISO/ANSI C++ Draft Working Paper versucht zu kodifizieren, welche Programme kompiliert werden und welche semantischen Auswirkungen ihre Ausführung haben wird, es unternimmt keinen Versuch, das binäre Laufzeitmodell von C++ zu standardisieren. Dieses Problem tritt zum ersten Mal auf, wenn ein Client versucht, eine Verknüpfung mit der Importbibliothek der FastString-DLL aus einer C++-Entwicklungsumgebung herzustellen außer diejenige, die zum Erstellen der FastString-DLL verwendet wird.
Das Auffüllen von Strukturen wird von verschiedenen Compilern unterschiedlich durchgeführt. Selbst wenn Sie den gleichen Compiler verwenden, kann die Ausrichtung für das Packen von Strukturen unterschiedlich sein, je nachdem, was Pragma-Paket Sie verwenden.
Nicht nur das, wenn Sie zwei Strukturen schreiben, deren Mitglieder sind exakt gleich, die nur Unterschied ist, dass die Reihenfolge, in der sie deklariert werden, unterschiedlich ist, dann kann die Größe jeder Struktur unterschiedlich sein (und ist es oft).
Sehen Sie sich zum Beispiel dies an,
struct A
{
char c;
char d;
int i;
};
struct B
{
char c;
int i;
char d;
};
int main() {
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
}
Kompilieren Sie es mit gcc-4.3.4
und Sie erhalten diese Ausgabe:
8
12
Das heißt, die Größen sind unterschiedlich, obwohl beide Strukturen die gleichen Mitglieder haben!
Das Fazit ist, dass der Standard nicht darüber spricht, wie das Auffüllen erfolgen soll, und daher können die Compiler jede Entscheidung treffen und Sie kann nicht Gehen Sie davon aus, dass alle Compiler die gleiche Entscheidung treffen.
Wenn Sie die Möglichkeit haben, die Struktur selbst zu entwerfen, sollte dies möglich sein. Die Grundidee ist, dass Sie es so entwerfen sollten, dass keine Füllbytes eingefügt werden müssen. Der zweite Trick besteht darin, dass Sie mit Unterschieden in der Endianität umgehen müssen.
Ich werde beschreiben, wie die Struktur mit Skalaren erstellt wird, aber Sie sollten in der Lage sein, verschachtelte Strukturen zu verwenden, solange Sie für jede enthaltene Struktur dasselbe Design anwenden.
Erstens ist eine grundlegende Tatsache in C und C++, dass die Ausrichtung eines Typs die Größe des Typs nicht überschreiten darf. Wenn dies der Fall wäre, wäre es nicht möglich, Speicher mit zuzuweisen malloc(N*sizeof(the_type))
.
Gestalten Sie die Struktur, beginnend mit den größten Typen.
struct
{
uint64_t alpha;
uint32_t beta;
uint32_t gamma;
uint8_t delta;
Füllen Sie als Nächstes die Struktur manuell auf, damit Sie am Ende den größten Typ finden:
uint8_t pad8[3]; // Match uint32_t
uint32_t pad32; // Even number of uint32_t
}
Im nächsten Schritt muss entschieden werden, ob die Struktur im Little- oder Big-Endian-Format gespeichert werden soll. Der beste Weg ist, alle Elemente zu “tauschen”. vor Ort vor dem Schreiben oder nach dem Lesen der Struktur, wenn das Speicherformat nicht mit der Endianness des Hostsystems übereinstimmt.
Nein, es gibt keinen sicheren Weg. Zusätzlich zum Auffüllen müssen Sie sich mit unterschiedlicher Byte-Reihenfolge und unterschiedlichen Größen von integrierten Typen befassen.
Sie müssen ein Dateiformat definieren und Ihre Struktur in und aus diesem Format konvertieren. Serialisierungsbibliotheken (z. B. boost::serialization oder die Protokollpuffer von Google) können dabei helfen.
Lange Rede kurzer Sinn, nein. Es gibt keinen plattformunabhängigen, standardkonformen Umgang mit Padding.
Padding wird im Standard “Alignment” genannt und beginnt in 3.9/5 mit der Diskussion:
Objekttypen haben Ausrichtungsanforderungen (3.9.1, 3.9.2). Die Ausrichtung eines vollständigen Objekttyps ist ein implementierungsdefinierter ganzzahliger Wert, der eine Anzahl von Bytes darstellt; ein Objekt wird einer Adresse zugewiesen, die die Ausrichtungsanforderungen seines Objekttyps erfüllt.
Aber von dort aus geht es weiter und windet sich in viele dunkle Ecken des Standards. Die Ausrichtung ist “implementierungsdefiniert”, was bedeutet, dass sie zwischen verschiedenen Compilern oder sogar zwischen Adressmodellen (dh 32-Bit/64-Bit) unter dem unterschiedlich sein kann gleich Compiler.
Wenn Sie keine wirklich strengen Leistungsanforderungen haben, sollten Sie Ihre Daten in einem anderen Format auf Disc speichern, z. B. Zeichenketten. Viele Hochleistungsprotokolle senden alles mit Strings, obwohl das natürliche Format etwas anderes sein könnte. Zum Beispiel sendet ein Austausch-Feed mit niedriger Latenz, an dem ich kürzlich gearbeitet habe, Datumsangaben als Zeichenfolgen im folgenden Format: “20110321” und Zeiten werden ähnlich gesendet: “141055.200”. Obwohl dieser Austausch-Feed den ganzen Tag über 5 Millionen Nachrichten pro Sekunde sendet, verwenden sie immer noch Strings für alles, weil sie auf diese Weise Endianness und andere Probleme vermeiden können.
9927900cookie-checkStrukturauffüllung in C++yes
Die Effizienz (Leistung), die durch die Ausführung binärer I/O gewonnen wird, rechtfertigt oft nicht die Ausgaben für Forschung, Design, Entwicklung und insbesondere Debugging und Wartung. Quellcode sollte einfach zu verstehen sein, aber nicht einfacher.
– Thomas Matthäus
22. März 2011 um 22:24 Uhr