Zero-Padding bei structs erzwingen, portabel?



  • Hallo,
    ich suche eine portable Lösung, um beliebige structs in Dateien zu schreiben, à la
    fwrite(X, sizeof(X), 1, out)
    Das Problem hierbei ist ja das unterschiedliche Alignment bei verschiedenen Compilern.
    Gibt es eine portable Lösung, wie ich das gleiche Alignment (nämlich gar keins, sprich kein Padding zwischen den struct-Members und die Reihenfolge im Speicher wie deklariert) auf allen Compilern erzwingen kann?



  • nein, dass gibt es nicht. Schreib einfach nicht so binäre quatsch Dateien. Die sind nämlich inkompatibel dadurch.

    schreib lieber die Member einzelnd im Text Modus. Dann kannst du die einfach laden.



  • Das struct Verfahren ist nicht portabel, speziell nicht zwischen Platformen wegen dem padding und den Zahlenformaten Litle und Big Endian.

    Im Gegensatz zu kingruedi würdeich die Daten nicht im textmodus schreiben, sondern binaer.
    Ich würde mir für jede Struct eine Schreib und eine Lesefunktion schreiben,
    die jedes member der struct einzeln schreibt.
    Wenn ich sicher weis das ich nicht auf eine System mit einer anderen Bytereihenfolge
    portieren muss, kann ich das mit fwrite/fread {int16, int32, float, double, char,..} erledigen.
    Bei Strings würde ich als Konvention einführen das ich erst eine int16/int32 schreibe der
    die Länge des Strings inclusive der \0 beinhaltet und den String unmittelbar danach mit \0.

    Wenn ich zwischen systemen mit little und Big Endian Zahlenformat portieren muss,
    gehe ich soweit, das ich auch die simple Types durch eigene Funktionen als
    Bytes schreibe. Uch weis dann genau wo welches Byte eines Elements liegt
    und bin somit nicht mehr von little und Big Endian abhängig,

    Falls noch Fragen sind reposten.

    🙂 P.S. Kann mir einer sagen ob die x86 CPU´s little oder Big Endian sind.



  • warum binär ausgeben? Wenn man sich auch einfach die ganzen Portierungsprobleme sparen kann. Ist ja nicht nur Litte/Big-Endian. Was machst du, wenn du zB von einer 32Bit Platform auf eine 64Bit Platform wechselst? Warum sollte ich mir unnötige Klötze in den Weg räumen?

    x86 ist little endian



  • 1 weil ich auf diese Weise deutlich Speicherplatz spare,
    2 weil der Zugriff beim Lesen und Schreiben schneller ist,
    3 weil die Daten nicht trivial lesbar und damit nicht einfach änderbar sind.
    4 weil ich durch die Konvertierung der float und double Zahlen keine Rundungsfehler bekomme.

    Zu 1: Int16 2 Byte im Gegensatz zu maximal 6 Byte + Delimiter (-32768,0,65536)
    Int32 4 Byte im Gegensatz zu maximal 11 BGyte + Delimiter
    ....
    double 8Byte im Gegensatz zu 17 Byte für die Mantisse 6 Byte Exponent Summe 23 Byte + Delimiter
    char 4 Byte + Stringlänge im Gegensatz zu Stringlänge

    Zu 2: Schau das zu lesende Zeichenvolumen an, typischerweise würde ich sagen das binaer Datein mindesten einen Faktor 2 kleiner sind

    Zu 3: der alte Spruch "ich hab mir nur die autoexec.bat angeschaut"
    Womit
    mit Word und dann gespeichert.
    Hier gibts keinen Schutz gegen Manipulation sondern nur gegen DAU (Dümmster anzunehmender User)

    Zu 4: Wenn man nicht mit maximaler Lönge die float/double Zahlen darstellt erzeugt jedes Speichern typischerweise ein verschlechtern der Daten
    durch die Konvertierung in .printf und lesen mit .scanf oder ähnliches



  • 1 weil ich auf diese Weise deutlich Speicherplatz spare

    Je nach Anwendungsbereich, kann das natürlich ein gutes Argument sein. Wenn ich auf einem Mikrocontroller arbeite, kann der Speicherplatz wichtig sein. Bei Desktop oder Server Anwendungen, sind die paar byte aber idr. egal und txt Dateien kann man wunderbar kompremieren.

    2 weil der Zugriff beim Lesen und Schreiben schneller ist,

    das stimmt auch wieder und kann wieder bei speziellen Anwendungen wichtig sein. Aber bei den üblichen Anwendungen, ist das eh egal. Wobei wahrscheinlich die meiste Zeit eh davon verbraucht wird, die Daten vom Datenträger zu laden.

    3 weil die Daten nicht trivial lesbar und damit nicht einfach änderbar sind.

    und hier kommt es. Das ist IMHO ein Nachteil. Wenn man ein Text Format nimmt, kann man sich mit einer beliebigen Script Sprache (zB. Perl) einfach ein kleines Auswertungsprogramm etc. schreiben oder wenn die Anwendung unsinns Daten erstellt, kann man diese leicht per Script (oder zu Not) per Editor bearbeiten.

    Das dies von vielen nicht unterschätzt wird, zeigt, dass XML jetzt überall eingesetzt wird (auch wenn ich kein XML Fan bin!)

    Ein DAU wird nicht an der Datei rumfummeln und wenn, wird es nur schlimmer, wenn er eine Binär Datei mit Word bearbeitet 🙂

    4 weil ich durch die Konvertierung der float und double Zahlen keine Rundungsfehler bekomme.

    bei einer normalen Text Datei erhält man auch keine Rundungsfehler. Man erhält eher Fehler, weil ein Kerl Daten, die die Alter Anwendung erstellt hat, mit der neuen Version benutzen will, nur leider wurde diese mit einem anderen Compiler erstellt und peng. Ganz davon zu schweigen, wenn jemand mal die Platform wechseln will.



  • @kingrüdi
    Zweite Runde
    Zu 1 & 2 Teilweise hast du recht. Bei unseren Programmen, mit den wir die Prüflinge testen werden, Messdaten gesammelt. Für einen der Prüflingstypen werden pro Testlauf ca 400 MB Binaerdaten gesammelt. Diese müssen über ein 10Mbit Netzwerk gespeichert werden. Zum Auswerten haben wir Programme geschrieben die diese Rohdaten in ASCII darstellung umsetzten. Zum Glück sind nur Int16 Zahlen drinn, Diese ASCII DAtein haben summen 1,2GB
    Die werden dann lokal erzeugt und anschließend mit awk, grep, gnuplot, Perl und eigenen Auswerteprogrammen bearbeitet. Du siehst also nicht nur bei Microcontrollern ist Platzsparen (Denkmal an die Transferzeit mit 10 Mbit zum Switch dann über einen Backbone mit 100MBit/1GBit zum Server in einem System mit ca 800 Computern) sinnvoll.

    Zu 3 Hier bin ich zweigeteilt.
    - Geht es um Konfigurationsdateien, ini-Dateien, Kommunikation zwischen Programmen, bin ich derselben Meinung wie du, Am besten ASCII und meistens das INI-File format von Windows.
    - Gehts um Messdaten, will ich diese Korrekturmöglichkeit eigentlich gar nicht, deshalb oftmals binaer, wobei natürlich das Format offengelegt ist.

    Aber an dieser Stelle muss man eigentlich die Diskussion beenden, ich glaube wir kommen hier in den Bereich des persönlichen Geschmacks.
    Was für mich aber klar ist mann muss sich im Projekt der Vor- und Nachteile bewußt sein und die jeweils richtige Lösung auswählen.
    Von der Statistik her sind trotz meiner Argumenation für die Binaerlösung wohl 85% der von mir genutzten Dateien in ASCII.
    Ich bin auch einer der ersten die über Word und Wordperfect schimpfen, wenn wiedernmal eine Datei von dem Programm selbst zerschossen wurde.
    Die meisten meiner Dokumente schreibe ich in TEX, da weis ich auch in 10-15 Jahren ist der Inhalt der Source noch lesbar, im Gegensatz zu den tollen Word´s

    Ein DAU wird nicht an der Datei rumfummeln und wenn, wird es nur schlimmer, wenn er eine Binär Datei mit Word bearbeitet

    Aus schmerzlicher Erfahrung, DAU´s basteln immer an lesbaren Dateien herum, sie meine begriffen zu haben was da steht, vor binaeren Dateien haben sie Angst.
    Das geht sogar soweit, das wir in bestimmte Dateien in die letzte Zeile eine CRC32 Checksum eintragen

    [Checksum]
    Value=0x1245

    und das beim öffnen der Datei prüfen, um zu sehen ob sich nicht einer die Datei nur angekuckt hat.
    Ich unterscheide hier deutlich zwischen Manipulation und Dummheit. Gegen Dummheit hilft das, gegen Manipulation nicht.

    Zu 4

    bei einer normalen Text Datei erhält man auch keine Rundungsfehler. Man erhält eher Fehler, weil ein Kerl Daten, die die Alter Anwendung erstellt hat, mit der neuen Version benutzen will, nur leider wurde diese mit einem anderen Compiler erstellt und peng. Ganz davon zu schweigen, wenn jemand mal die Platform wechseln will.

    Wenn ich eine double Zahl nicht als $.17lf ausgebe, so daß ich alle signifikanten Stellen im ASCII-File stehen habe, wird beim einlesen ein
    anderer Wert gelesen als urspringlich da war. und somit habe ich Rundungsfehler.

    Was machst du, wenn du zB von einer 32Bit Platform auf eine 64Bit Platform wechselst?

    Deswegen hatte ich ja folgendes angegeben
    {int16, int32, float, double, char,..}
    wobei float für 32 Bit float
    und double für 64 Bit float steht. :p war halt schlampig :p
    Da ich die Zahlenformate definiert habe kann ich sie auch in 10 Jahren auf einer 128 Bit Maschine Byteweise lesen.



  • Du siehst also nicht nur bei Microcontrollern ist Platzsparen (Denkmal an die Transferzeit mit 10 Mbit zum Switch dann über einen Backbone mit 100MBit/1GBit zum Server in einem System mit ca 800 Computern) sinnvoll.

    wie gesagt, Textdaten kann man idr. noch gut mit Algorithmen wie bz2 komprimieren.

    - Gehts um Messdaten, will ich diese Korrekturmöglichkeit eigentlich gar nicht, deshalb oftmals binaer, wobei natürlich das Format offengelegt ist.

    geht ja nicht nur um Korrektur Möglichkeiten. So kann man auch leicht ein Script schreiben, dass die Daten auswertet und zB. nach Tex konvertiert oder als HTML Daten per WWW ausgibt oder in eine Datenbank einträgt oder den Systemverwalter alamiert, dass was nicht stimmt, zB wenn man ein Kühlhaus überwacht und die Temperatur steigt oder sogar automatisch Dinge starten (zB. beim Kühlhaus die Kühlung erhöhen). Bei einem Binär Format ist diese Arbeit unglaublich schwer.

    Wenn das Format in XML (auch wenn ich XML nicht mag!) ist, dann kann man zB. leicht mit einem Perl Script, die Daten bearbeiten.

    Wenn du befürchtest, dass die Daten verändert werden, kannst du ja die Checksumme einbauen

    Wenn ich eine double Zahl nicht als $.17lf ausgebe, so daß ich alle signifikanten Stellen im ASCII-File stehen habe, wird beim einlesen ein
    anderer Wert gelesen als urspringlich da war. und somit habe ich Rundungsfehler.

    Ich verstehe nicht, warum Rundungsfehler auftretten sollen, wenn ich ein double als Text Speicher und nicht Binär



  • kingruedi schrieb:

    Ich verstehe nicht, warum Rundungsfehler auftretten sollen, wenn ich ein double als Text Speicher und nicht Binär

    Das ist dann der Fall, wenn du nicht ALLE signifikanten Stellen ausgibst.

    Danke ihr beiden.
    In meinem Fall bin ich auf Binär-format angewiesen, denn das Format existiert bereits, ich definiere es nicht.
    Ich wollte nur wissen, ob es eine portable Möglichkeit gibt, die ganze Binärdatei als einen großen struct einzulesen/auszugeben (das Layout der Datei ist bekannt). Das scheint also nicht der Fall zu sein. Schade.
    Dann werd ich eben die Members einzeln durchgehen müssen.

    Zur Diskussion über die Verwendung von Binär vs. Text-Dateien möchte ich noch einwerfen, dass man zwischen Windows, Mac und Unix-Systemen noch das leidige Problem der verschiedenen Zeilenumbruchkonventionen hat (CR/LF auf Windows vs. LF auf Unix vs. CR auf Mac)
    Ein Problem, das bei Binärdateien nicht auftritt.



  • scrontch schrieb:

    kingruedi schrieb:

    Ich verstehe nicht, warum Rundungsfehler auftretten sollen, wenn ich ein double als Text Speicher und nicht Binär

    Das ist dann der Fall, wenn du nicht ALLE signifikanten Stellen ausgibst.

    Natürlich sollte man dann auch alles ausgeben 🙄

    scrontch schrieb:

    Zur Diskussion über die Verwendung von Binär vs. Text-Dateien möchte ich noch einwerfen, dass man zwischen Windows, Mac und Unix-Systemen noch das leidige Problem der verschiedenen Zeilenumbruchkonventionen hat (CR/LF auf Windows vs. LF auf Unix vs. CR auf Mac)
    Ein Problem, das bei Binärdateien nicht auftritt.

    Das Problem ist minimal. 1. Könnte man einfach CR/LF nehmen und alle Systeme sind zufrieden. 2. Wenn man sich ein eigenes Format einfallen lässt oder XML nimmt, ist das ja eh egal.



  • scrontch schrieb:

    Ich wollte nur wissen, ob es eine portable Möglichkeit gibt, die ganze Binärdatei als einen großen struct einzulesen/auszugeben (das Layout der Datei ist bekannt). Das scheint also nicht der Fall zu sein. Schade.
    Dann werd ich eben die Members einzeln durchgehen müssen.

    Portabel nicht, aber einzelne Compiler stellen dir die Möglichkeit zur Verfügung, gepackte Strukturen zu verwenden. Beim GCC geht das z.B. mit __attribute__((packed)) hinter der Strukturdefinition. MSVC hat meines Wissens ein #pragma dafür.



  • Das packed geht aber nur dann wenn alle Platformen die unterstützt werden sollen mindestens 1 Compiler haben der das unterstützt. Und wenn dieses Problem gelöst ist sollte man immer noch an das Little und BIG Endian Problem
    denken

    Auf x86 Architekur Schreiben, mit Apple lesen. Ergebnis sch....



  • PAD:
    Little/Big/Middle Endian Probleme hast du bei Binär Sachen immer, wenn du die Platform wechselst



  • 😃 Deswegen weise ich ja darauf hin, damit es nicht übersehen wird.

    Hab mit dem Problem genug zu tun da bei uns Daten zwischen 68360,68302, PowerPC und IBM-Pc über serielle Schnittstellen binaer ausgetauscht werden.


Anmelden zum Antworten