fwrite - ab 284 Byte gibt`s eines Gratis dazu ???



  • Hallo zusammen,

    ich habe ein recht merkwürdiges - und mich in den Wahnsinn treibendes - verhalten bei der Funktion fwrite.

    Es ist folgendermaßen:

    Ich habe ein HWND Array, was folgendermaßen deklariert wurde:

    HWND hwndAr[78];
    

    In diesem Array stehen verschiedene Window-Handles drin. Wie dem auch sei, lasse ich diese folgendermaßen in eine Datei schreiben:

    FILE* SaveFile;
    fopen_s( &SaveFile, "bla", "w+" );
    fwrite( &hwndAr, 
            78 * sizeof(HWND), 
            1, 
            SaveFile ); 
    fclose( SaveFile );
    

    Jetzt wunderte mich schon, dass die Datei nicht 312 ( wie es nach 78 * 4 ergeben müsste ), sondern 313 Byte groß ist.

    Als ich das Ganze dann folgendermaßen eingelesen hatte:

    HWND hwndAr[78];	
    fread_s( &hwndAr, 78 * sizeof(HWND), 78 * sizeof(HWND), 1, myFile );
    for( int i = 0; i < 78; i++ )
    {
        std::cout << i << "\t" << *(hwndAr + i)/*hwndAr[i]*/ << std::endl;
    }
    

    ... bemerkte ich, dass alle Werte bis auf die letzten 5 (?!) korrekt eingelesen wurden.

    Also bemühte ich einen Hex-Editor um zu überprüfen, was denn genau in der Datei steht, um den Fehler zunächst beim Schreiben zu suchen.

    Dabei stellte ich fest, dass zwischen dem 71. und dem 72. Eintrag (welche beide korrekt sind) ein weiteres Byte geschrieben wurde, welches dort nicht stehen dürfte.

    Ich hoffe, dass mir jemand weiterhelfen kann, denn auch wenn ich jeden Wert des Arrays einzeln rausschreibe, habe ich ab dem 72. Eintrag meines HWNDs dieses "Extra-Byte" ...



  • "w+b"


  • Administrator

    1. Was hat das mit C++ zu tun? fwrite ist eine C Funktion! Dein ganzer Code ist C und WinAPI. Wie kommst du auf die Idee, dass dies etwas mit C++ zu tun hat? *mal die Frage stellen will*
    2. Wie MFK gesagt hat, wenn du willst, dass die Daten 1:1 rausgehen, dann nutze das "b" . Wenn es nicht gesetzt ist, wird angenommen, dass du ein Textfile beschreiben willst, wodurch gewisse Änderungen automatisch vorgenommen werden. Zum Beispiel wird auf Windows aus einem \n ein \r\n .
    Ist zwar eine C++ Referenz, aber stimmt trotzdem als Lektüre:
    http://www.cplusplus.com/reference/clibrary/cstdio/fopen.html

    Grüssli



  • Das 313. Zeichen müsste EOF sein, also ganz normal, dass die Datei 1 Byte größer ist.



  • Dravere schrieb:

    1. Was hat das mit C++ zu tun?

    Na aber da steht doch cout! 😃 😉


  • Administrator

    _matze schrieb:

    Dravere schrieb:

    1. Was hat das mit C++ zu tun?

    Na aber da steht doch cout! 😃 😉

    🤡
    Oha, unter all dem C Code ganz übersehen. Und sogar ein std::endl dahinter. Ich glaube aber, dass ich meine Frage trotzdem so stehen lassen kann. Vor allem, da sich die Frage um fwrite / fopen und co dreht, was wirklich nichts mit C++ zu tun hat. Sogar wenn man in C++ programmiert, würde ich mit so eine Frage ins C Forum. Kommt schliesslich von denen :p

    Grüssli



  • Ich glaube, wenn ich jetzt anfangen würde von wegen "die Funktionen sind doch Bestandteil von C++...", dann würdest du entgültig auf die Palme gehen, was? 😉

    Nee, hast schon Recht...



  • feigling schrieb:

    Das 313. Zeichen müsste EOF sein, also ganz normal, dass die Datei 1 Byte größer ist.

    Es gibt kein Zeichen "EOF". Leere Dateien sind auch nicht 1 Byte groß.



  • feigling schrieb:

    Das 313. Zeichen müsste EOF sein

    Huh? EOF-Zeichen am Ende von Dateien gibt's nicht.



  • Dravere schrieb:

    1. Was hat das mit C++ zu tun? fwrite ist eine C Funktion! Dein ganzer Code ist C und WinAPI. Wie kommst du auf die Idee, dass dies etwas mit C++ zu tun hat? *mal die Frage stellen will*
    2. Wie MFK gesagt hat, wenn du willst, dass die Daten 1:1 rausgehen, dann nutze das "b" . Wenn es nicht gesetzt ist, wird angenommen, dass du ein Textfile beschreiben willst, wodurch gewisse Änderungen automatisch vorgenommen werden. Zum Beispiel wird auf Windows aus einem \n ein \r\n .
    Ist zwar eine C++ Referenz, aber stimmt trotzdem als Lektüre:
    http://www.cplusplus.com/reference/clibrary/cstdio/fopen.html

    Grüssli

    Und was genau ist unter der Referenz nun mehr C++ als mein Code? Steht doch genau so auch dort drin.

    Also liegt mein Problem darin, dass ich "w+b" schreiben muss. Ich gehe davon aus, dass das "b" für binary steht, aber kann mir mal jemand sagen, woher man das wissen soll, wenn das nirgendwo - auch nicht in der Visual Studio Hilfe - erwähnt wird?



  • FrEEzE2046 schrieb:

    kann mir mal jemand sagen, woher man das wissen soll, wenn das nirgendwo - auch nicht in der Visual Studio Hilfe - erwähnt wird?

    Also in der MSDN (fopen) steht es drin:

    MSDN schrieb:

    Also, in text mode, carriage return–linefeed combinations are translated into single linefeeds on input, and linefeed characters are translated to carriage return–linefeed combinations on output [...]

    b Open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed.


  • Administrator

    FrEEzE2046 schrieb:

    Und was genau ist unter der Referenz nun mehr C++ als mein Code? Steht doch genau so auch dort drin.

    Ich habe nie gesagt, dass die verlinkte Referenz mehr C++ Code aufzeigt als deiner.
    Die Sache ist, du nutzt C Funktionen. Die sind zwar über <cstdio> auch in C++ nutzbar, doch normalerweise nutzt man in C++ die IO Streamklassen, weil diese zahlreiche Vorteile gegenüber den C Funktionen haben. Sofern man C++ programmiert.

    FrEEzE2046 schrieb:

    Also liegt mein Problem darin, dass ich "w+b" schreiben muss. Ich gehe davon aus, dass das "b" für binary steht, ...

    Zu beidem, ja.

    FrEEzE2046 schrieb:

    aber kann mir mal jemand sagen, woher man das wissen soll, wenn das nirgendwo - auch nicht in der Visual Studio Hilfe - erwähnt wird?

    Durch ein gutes Buch?
    Durch eine gute Referenz?
    In dem man die MSDN richtig liest:
    http://msdn.microsoft.com/en-us/library/yeby3zcb.aspx
    (steht da auch drin, somit auch in der VS Hilfe)

    Grüssli



  • Badestrand schrieb:

    feigling schrieb:

    Das 313. Zeichen müsste EOF sein

    Huh? EOF-Zeichen am Ende von Dateien gibt's nicht.

    Oha, echt? :o Dann verwechse ich das mit irgendwas anderem. Ka, wie ich dann drauf komme, dass es bei Dateien noch ein Abschlusstoken gibt. Sorry.



  • mmmh, dass hab ich echt nicht gelesen. Ich habe den Fehler aber auch eher bei fwrite gesucht.

    Wie könnte ich mir denn am besten mit C++ - Funktionen die Daten speichern?


  • Administrator

    feigling schrieb:

    Badestrand schrieb:

    feigling schrieb:

    Das 313. Zeichen müsste EOF sein

    Huh? EOF-Zeichen am Ende von Dateien gibt's nicht.

    Oha, echt? :o Dann verwechse ich das mit irgendwas anderem. Ka, wie ich dann drauf komme, dass es bei Dateien noch ein Abschlusstoken gibt. Sorry.

    Lass dich von denen nicht verwirren. Es gibt EOF Zeichen:
    http://de.wikipedia.org/wiki/End_of_File

    Allerdings werden die meistens nicht reingeschrieben. Das Problem mit dem EOF Zeichen hat man eher beim Lesen von binären Daten. Beim Schreiben wird zwar kein EOF Zeichen erzeugt, beim Lesen aber durchaus erkannt.

    @FrEEzE2046,
    http://magazin.c-plusplus.net/artikel/Ein- und Ausgabe in CPlusPlus - IO-Streams

    Ist zwar jetzt mehr auf Text bezogen. Aber ansonsten halt die Referenz zu den Filestreams in C++:
    http://www.cplusplus.com/reference/iostream/ifstream/
    http://www.cplusplus.com/reference/iostream/ofstream/
    http://www.cplusplus.com/reference/iostream/fstream/

    Am besten lernst du darüber, wenn du ein gutes C++ Buch liest.

    Grüssli



  • Dravere schrieb:

    Ich habe nie gesagt, dass die verlinkte Referenz mehr C++ Code aufzeigt als deiner.
    Die Sache ist, du nutzt C Funktionen. Die sind zwar über <cstdio> auch in C++ nutzbar, doch normalerweise nutzt man in C++ die IO Streamklassen, weil diese zahlreiche Vorteile gegenüber den C Funktionen haben. Sofern man C++ programmiert.

    Also ich benutze auch fats ausschließlich fopen und fread/fwrite, den Vorteil in fstreams gegenüber der C Variante hab ich bisher nicht gesehen, sogar eher Nachteile weil die C Version void* annimt wärend fstream unbedingt char* will.



  • Dravere schrieb:

    feigling schrieb:

    Badestrand schrieb:

    feigling schrieb:

    Das 313. Zeichen müsste EOF sein

    Huh? EOF-Zeichen am Ende von Dateien gibt's nicht.

    Oha, echt? :o Dann verwechse ich das mit irgendwas anderem. Ka, wie ich dann drauf komme, dass es bei Dateien noch ein Abschlusstoken gibt. Sorry.

    Lass dich von denen nicht verwirren. Es gibt EOF Zeichen:
    http://de.wikipedia.org/wiki/End_of_File

    Allerdings werden die meistens nicht reingeschrieben. Das Problem mit dem EOF Zeichen hat man eher beim Lesen von binären Daten. Beim Schreiben wird zwar kein EOF Zeichen erzeugt, beim Lesen aber durchaus erkannt.

    Dass es EOF gibt, ist klar. Ich hatte aber auch irgendwie im Kopf, dass EOF auch in die Datei geschrieben wird, zumindest wenn man nicht im Binärmodus schreibt.

    Edit:

    Wiki schrieb:

    Historisch fügte Microsoft DOS das ASCII-Steuerzeichen SUB 0x1A (eben Strg-Z) tatsächlich an das Ende einer Datei. Die Kompatibilität zu älteren Systemen (z. B. CP/M) wäre sonst nicht zu gewährleisten gewesen.

    Ok, da stehts doch, dass es zumindest früher auch geschrieben wurde.



  • mmmh,

    wird nicht vielmehr die aktuelle Position in der Datei mit der letzten Position verglichen und somit das Dateiende erkannt?


  • Administrator

    Xebov schrieb:

    Also ich benutze auch fats ausschließlich fopen und fread/fwrite, den Vorteil in fstreams gegenüber der C Variante hab ich bisher nicht gesehen, sogar eher Nachteile weil die C Version void* annimt wärend fstream unbedingt char* will.

    Und da habe ich schon Leute gesehen, welche dann das hier machen:

    class Derived
      : public Base
    {
      // Ein paar virtuelle Funktionen.
    };
    
    // ...
    Derived d;
    fwrite(d, sizeof(d), 1, file);
    

    Funktioniert ja, weil es kompiliert. Bei einem char* kommen sie immerhin angelaufen und fragen nach, wie man den Typen in einen char* umwandelt. Ist wie bei Exceptions, man kann ein catch machen und die Neulinge davor bewahren schlimmes zu machen 😃

    Der char* führt einem dann auch noch dazu zu überlegen, wie die Daten nun geschrieben werden. BE? LE?
    Wenn man dann entsprechend die Sache anpassen will, nützt auch das void* von fwrite nichts mehr, da man jedes Byte in der richtigen Reihenfolge reinbekommen muss.

    Ansonsten bieten die Streams halt mehr Möglichkeiten. Vor allem durch die gemeinsamen Basisklassen. So kann man einfach einen std::basic_istream erwarten, wohin dann tatsächlich geschrieben wir, kann man dem Nutzer freilassen. Er kann so die Sache in einen Puffer umleiten oder auch gleich irgendwo anders hinschicken.
    Auch bekommt man über die Streams gleich Exceptions, welche man zwar immer manuell selber setzen muss, also dass sie geworfen werden sollen, aber immerhin.
    http://www.cplusplus.com/reference/iostream/ios/exceptions.html

    Werner Salomon hat glaube ich hier irgendwo auch mal eine Streamklasse gezeigt, welche etwas angenehmer zu handhaben ist für das binäre Lesen und Schreiben.

    Grüssli



  • Dravere schrieb:

    Funktioniert ja, weil es kompiliert. Bei einem char* kommen sie immerhin angelaufen und fragen nach, wie man den Typen in einen char* umwandelt. Ist wie bei Exceptions, man kann ein catch machen und die Neulinge davor bewahren schlimmes zu machen 😃

    Ja gut ok, aber ich denke wer sowas einsetzt solte schon wissen was er da tut, es gibt zu dem Thema ja imerhin genug Dokumentation das sowas nicht passieren sollte.


Log in to reply