Filestream write() - Serialisierung von C++-Klassen



  • Ok, danke für die Aufklärung, besonders an SeppJ.

    Habe zum Thema Padding hier noch zwei hilfreiche Quellen gefunden.

    http://msdn.microsoft.com/en-us/library/71kf49f1(v=vs.80).aspx

    http://en.wikipedia.org/wiki/Data_structure_alignment#Data_structure_padding



  • Katzenzunge_n schrieb:

    Inwiefern iteriert write() in einer Schleife?

    void write(char* data, int size)
    {
        while(size--)
            write_char(*data++);
    }
    

    So in etwa _könnte_ write funktionieren. Muss es aber nicht. Nirgens steht geschrieben, ob write nicht auch z.B. memmove verwenden könnte. Aber man kann sich das in etwa so vorstellen.



  • Was genau write intern verwendet, dürfte auch davon abhängen, welchen Stream du angegeben hast. Es dürfte wohl die streambuf::sputn() für die tatsächliche Ausgabe bemühen. Wenn das nicht für den speziellen Stream-Typ optimiert wurde, läuft diese wiederum auf eine Schleife für die byteweise Ausgabe hinaus.
    (die Optimierungen können dann in einem direkten Aufruf von memcpy(), fwrite() oder std::string::append() bestehen - je nachdem, worüber du redest)



  • ofstream::write nutzt doch unter der Haube fwrite() ?
    Zumindestens in der MSVC STl Implementierung.



  • 314159265358979 schrieb:

    Katzenzunge_n schrieb:

    Inwiefern iteriert write() in einer Schleife?

    void write(char* data, int size)
    {
        while(size--)
            write_char(*data++);
    }
    

    So in etwa _könnte_ write funktionieren. Muss es aber nicht. Nirgens steht geschrieben, ob write nicht auch z.B. memmove verwenden könnte. Aber man kann sich das in etwa so vorstellen.

    Hi!

    Das ist mir schon klar. 😉

    Es ging dabei mehr um die Frage, wie write() über die Datenmember iteriert? SeppJ hat ja bereits erklärt das beim Casten einfach aus dem Speicher sequentiell geschrieben wird und er hat auch erklärt wie diese in einem Struct abgebildet werden.

    Es ging also nicht darum wie write() funktioniert, sondern was von write() überhaupt beim Casten einer Klasseninstanz geschrieben wird.



  • Ethon schrieb:

    ofstream::write nutzt doch unter der Haube fwrite() ?
    Zumindestens in der MSVC STl Implementierung.

    Ist absolut erlaubt, aber vom Standard nicht gearantiert - genausogut könnte es hinter den Kulissen mit man: write(2) arbeiten oder mit einer speziell dafür vom Compiler-Hersteller geschriebenen Bibliothek.



  • Padding ist durchaus interessant.

    #include <iostream>
    using namespace std;
    
    class A 
    {
    public:
        char a;
        char b;
        int c;
    };
    
    class B 
    {
    public:
        char a;
        int c;
        char b;
    };
    
    int main(void) 
    {
        int sizeA = sizeof(A);
        int sizeB = sizeof(B);
    
        cout << "A = " << sizeA << endl;
        cout << "B = " << sizeB << endl;
    
        return 0;
    }
    

    Mein VC++ liefert mir hier die Ausgabe:

    A = 8
    B = 12
    

    sizeof(9 auf einer Klasse aufzurufen scheint wirklich ziemlich abenteuerlich zu sein.



  • Und jetzt füge Mal virtuelle Funktionen hinzu...
    ~Ich nehme an, dir ist klar, dass struct das selbe ist wie class, nur mit einem standardmäßigem public-Sichtbarkeitsbereich~



  • Oberon_0 schrieb:

    Ich nehme an, dir ist klar, dass struct das selbe ist wie class, nur mit einem standardmäßigem public-Sichtbarkeitsbereich

    Ist mir bekannt.

    Oberon_0 schrieb:

    Und jetzt füge Mal virtuelle Funktionen hinzu...

    Interessant. sizeof() liefert mit einer virtielle Funktion nun 16, statt 12 zurück. Dürfte wohl der zusätzlich Pointer (0) sein?



  • Interessant. sizeof() liefert mit einer virtielle Funktion nun 16, statt 12 zurück. Dürfte wohl der zusätzlich Pointer (0) sein?

    Ja, der Pointer zur Functiontable.
    Und jetzt erbe die Klasse, und füg neue virtuelle Funktionen dazu. 😉

    Aber ernsthaft: Sachen in eine POD-Representation bringen und direkt schreiben/lesen ist imo keine so schlechte Idee, man sollte halt compilerunabhängig Padding/Alignment festsetzen und auf die Endianess aufpassen.



  • Ethon schrieb:

    Aber ernsthaft: Sachen in eine POD-Representation bringen und direkt schreiben/lesen ist imo keine so schlechte Idee, man sollte halt compilerunabhängig Padding/Alignment festsetzen und auf die Endianess aufpassen.

    Meiner Ansicht nach ist davon eher strikt abzuraten, zumindest wenn man in ANSII C++ programmiert.

    Dann lieber Boost verwenden oder den operator<< überladen und die Daten selbst im festen Format schreiben.

    Alles andere sieht mir angesichts der Sachlage nach ziemlichen Murks aus.



  • Katzenzunge_n schrieb:

    Ethon schrieb:

    Aber ernsthaft: Sachen in eine POD-Representation bringen und direkt schreiben/lesen ist imo keine so schlechte Idee, man sollte halt compilerunabhängig Padding/Alignment festsetzen und auf die Endianess aufpassen.

    Meiner Ansicht nach ist davon eher strikt abzuraten, zumindest wenn man in ANSII C++ programmiert.

    Dann lieber Boost verwenden oder den operator<< überladen und die Daten selbst im festen Format schreiben.

    Alles andere sieht mir angesichts der Sachlage nach ziemlichen Murks aus.

    Die meisten Fileformate sind allerdings binär. Was auch einen Grund hat. 😉
    Geringerer Platzbedarf und man muss nicht parsen.

    Wer möchte denn 100MB große Mp3 Dateien haben, die mehrere Sekunden laden?



  • Nur sind solche Formate dann standardisiert und hängen nicht von Compiler und Plattform ab. Natürlich machen Binärformate Sinn, aber sobald du sowas portabel hinkriegen willst, musst du eh memberweise vorgehen. Zumal in C++ der Grossteil der Klassen keine PODs sind.

    Du kannst das Ganze auch abstrahieren, wie das Boost.Serialization mit seinen Archiven macht. Auf der einen Seite schreibst und liest du die einzelnen Member, auf der anderen Seite hast du ein Archiv, welches die aufgerufenen Schreib-/Lesefunktionen umsetzt. Diese Umsetzung bestimmt dann das eigentliche Format. Das kann sowohl Text als auch binäre Daten sein.


Anmelden zum Antworten