Welchen Nutzen hat die Nullpunktverschiebung in der Funktion fseek() mit SEEK_CUR?

Lesezeit: 4 Minuten

Benutzeravatar von osmangokalp
Osmangokalp

while (fread(&product, sizeof(Product), 1, file) == 1) {
        product.price *= 2.0;
        fseek(file, -sizeof(Product), SEEK_CUR);
        fwrite(&product, sizeof(Product), 1, file);
        fseek(file, 0, SEEK_CUR);
}

Mit dem obigen Code habe ich versucht, den Preis jedes Produkts in der Binärdatei zu verdoppeln, wobei jeder Datensatz eine Instanz einer Produktstruktur ist. Als ich diesen Code ausgeführt habe, wurden alle Preise in der Datei korrekt aktualisiert.

So weit ich weiß, fread Verschiebt den Dateizeiger automatisch auf den nächsten Datensatz. Mit dem ersten fseek, verschiebt der Code den Dateizeiger zurück an den Anfang des Datensatzes. Dann aktualisiert es es mit fwrite. fwrite Verschiebt den Dateizeiger automatisch auf den nächsten Datensatz. In der while-Schleife fread sollte mit dem Lesen des nächsten Datensatzes fortfahren und so weiter.

Es scheint, dass fseek(file, 0, SEEK_CUR); ist hier unnötig. Wenn ich es jedoch entferne, gerät der Code in eine Endlosschleife. Ich kann nicht herausfinden, warum das passiert.

Ich habe versucht, den Wert des Dateizeigers zu beobachten ftell. Aber ich habe danach keine Wertänderung festgestellt fseek(file, 0, SEEK_CUR);.

  • Hinweis: Besserer Code würde die Rückgabewerte von überprüfen fwrite() Und fseek().

    – chux – Monica wieder einsetzen

    14. Mai um 4:08

Benutzer-Avatar von Andreas Wenzel
Andreas Wenzel

Wenn ein Stream sowohl zum Lesen als auch zum Schreiben geöffnet ist, dürfen Sie nicht direkt zwischen Lesen und Schreiben wechseln. §7.21.5.3 ¶7 der ISO C11-Norm gibt folgendes an:

Wenn eine Datei im Aktualisierungsmodus geöffnet wird („+“ als zweites oder drittes Zeichen in der obigen Liste der Modusargumentwerte), können sowohl Eingabe als auch Ausgabe für den zugehörigen Stream durchgeführt werden. Auf die Ausgabe darf jedoch nicht direkt eine Eingabe folgen, ohne dass die Flush-Funktion oder eine Dateipositionierungsfunktion (fseek, fsetpos oder rewind) aufgerufen wird, und auf die Eingabe darf nicht direkt eine Ausgabe folgen, ohne dass eine Dateipositionierung aufgerufen wird Funktion, es sei denn, die Eingabeoperation stößt auf ein Dateiende.

Wenn Sie die Zeile entfernen

fseek(file, 0, SEEK_CUR);

dann verstößt Ihr Programm gegen diese Regel, die aufgerufen wird undefiniertes Verhalten. Das bedeutet, dass alles passieren kann, einschließlich der Möglichkeit, dass Ihr Programm in einer Endlosschleife stecken bleibt.

  • Gute Antwort. Sie können auch erwähnen, dass der veröffentlichte Code kein definiertes Verhalten aufweist, wenn die Datei nicht im Binärmodus geöffnet wird.

    – chqrlie

    14. Mai um 19:57 Uhr

  • @chqrlie: Da OP angegeben hat, dass die Datei binär ist, gehe ich davon aus, dass die Datei entweder im Binärmodus geöffnet wurde oder dass OP eine Plattform verwendet, auf der es keinen Unterschied zwischen Textmodus und Binärmodus gibt (z. B. POSIX/Linux). Allerdings haben Sie damit Recht §7.21.9.2 ¶4 des ISO C11-Standardsdie Linie fseek(file, -sizeof(Product), SEEK_CUR); ruft undefiniertes Verhalten im Textmodus auf. Auf POSIX-Plattformen (z. B. Linux) ist das Verhalten jedoch definiert.

    – Andreas Wenzel

    15. Mai um 10:43 Uhr


  • Neugierig, ob fflush() kann es tun oder nicht.

    – Josua

    15. Mai um 19:36 Uhr

  • @chqrlie: Es sei denn Product ist ein char[] Er befindet sich im Binärmodus oder hat undefiniertes Verhalten aufgerufen fwrite().

    – Josua

    15. Mai um 19:37 Uhr

  • @Joshua: Wie in der Antwort angegeben, der Anruf fseek(file, 0, SEEK_CUR); kann ersetzt werden durch fflush(file); und das Spülen könnte zuverlässiger, aber auch teurer sein.

    – chqrlie

    16. Mai um 12:28

Einige Dateisysteme, die bei der Durchführung zufälliger Suchvorgänge eher langsam sind, sind so konzipiert, dass sie mithilfe separater Lese- und Schreibzeiger eine effiziente Verarbeitung von Lese-, Änderungs- und Schreibvorgängen für eine Folge von Datensätzen ermöglichen. Ein Programm wie Ihres kann möglicherweise darauf verzichten fseek Vorgänge setzten ausschließlich voraus, dass die Menge der gelesenen Daten mit der Menge der geschriebenen Daten übereinstimmte, und würden ohne diese möglicherweise viel schneller ausgeführt fseek() Operationen als es ausgeführt werden würde, wenn sie enthalten wären.

Die Implementierung der AC-Standardbibliothek müsste nachverfolgen, ob der letzte an einer Datei ausgeführte Vorgang ein Schreib- oder Lesevorgang war, also ein relativer Vorgang fseek() könnte relativ zur aktuellen Leseposition oder der aktuellen Schreibposition arbeiten, abhängig davon, welche Art von Operation zuletzt ausgeführt wurde, könnte es aber ermöglichen, dass geschriebene Programme duale Dateizeiger ausnutzen, um die damit verbundenen Leistungssteigerungen zu erzielen, wenn sie auf Systeme abzielen, die sie verwenden.

Obwohl der Standard das Verhalten beim Schreiben und Lesen ohne Eingreifen hätte kategorisieren können fseek() Als Implementierungsdefiniert würde dies bedeuten, dass Implementierungen versuchen sollten, sich in einer konsistenten dokumentierten Weise zu verhalten, selbst wenn sie auf Plattformen mit Eckfallverhalten abzielen, das nicht immer vorhersehbar ist.

  • Ich wollte diese Antwort schreiben! Das gemeldete Schleifenverhalten des OP, wenn das zweite fseek() weggelassen wird, steht im Einklang damit, dass seine Laufzeit über separate Lese- und Schreibzeiger verfügt, die durch fseek() synchronisiert werden.

    – grahamj42

    15. Mai um 20:38 Uhr

  • @grahamj42: Es ist wichtig anzumerken, dass der Standard dazu gedacht war, Programmierern eine „Kampfchance“ zu geben, portable Programme zu schreiben, und nicht, um sicherzustellen, dass Programmierer mit portablem Code das gleiche Leistungsniveau erreichen können, das mit nicht-portablen Konstrukten erreichbar wäre. Wenn ein System darauf ausgelegt ist, die Leistung des Lese-, Änderungs- und Schreibmusters ohne fseek zu maximieren, und nicht darauf ausgelegt ist, die fseek-Leistung zu optimieren, kann die Verwendung von zwei fseeks pro Datensatz die Leistung um eine Größenordnung beeinträchtigen.

    – Superkatze

    16. Mai um 16:56 Uhr

1454360cookie-checkWelchen Nutzen hat die Nullpunktverschiebung in der Funktion fseek() mit SEEK_CUR?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy