Warum sucht der C ++ - Standard nach Dateien, die so suchen, wie sie es tun?

17

C ++ verwendet den streamoffTyp, um einen Offset innerhalb eines (Datei-) Streams darzustellen, und ist in [stream.types] wie folgt definiert:

using streamoff = implementation-defined ;

Der Typ Streamoff ist ein Synonym für einen der vorzeichenbehafteten integralen Grundtypen mit ausreichender Größe, um die maximal mögliche Dateigröße für das Betriebssystem darzustellen. 287)

287) Typischerweise lang lang.

Dies ist sinnvoll, da damit große Dateien gesucht werden können (im Gegensatz zur Verwendung long, die möglicherweise nur 32 Bit breit ist).

[filebuf.virtuals] definiert basic_filebufdie Funktion zum Suchen in einer Datei wie folgt:

pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override;

off_typeist äquivalent zu streamoff, siehe [iostreams.limits.pos]. Der Standard erklärt dann jedoch die Auswirkungen der Funktion. Ich bin irritiert über den allerletzten Satz, für den ein Anruf erforderlich ist fseek:

Effekte : widthBezeichnen a_codecvt.encoding(). Wenn is_open() == falseoder off != 0 && width <= 0, schlägt der Positionierungsvorgang fehl. Wenn andernfalls way != basic_ios::curoder off != 0, und wenn die letzte Operation ausgegeben wurde, aktualisieren Sie die Ausgabesequenz und schreiben Sie eine beliebige Verschiebungssequenz. Suchen Sie als nächstes die neue Position: if width > 0, call fseek(file, width * off, whence), andernfalls call fseek(file, 0, whence).

fseekakzeptiert einen longParameter. Wenn off_typeund streamoffdefiniert sind als long long(wie vom Standard vorgeschlagen), kann dies zu einer Abwärtskonvertierung auf longbeim Anruf führen fseek(file, width * off, whence)(was zu möglicherweise schwer zu diagnostizierenden Fehlern führt). Dies stellt die gesamte Begründung für die Einführung des streamoffTyps in Frage .

Ist dies beabsichtigt oder ein Fehler in der Norm?

jceed2
quelle
8
Defekt sieht aus wie.
Yakk - Adam Nevraumont
Ich denke ich sehe, dass gcc libstdc ++ fseeko64 verwendet .
KamilCuk
1
Offhand, es sieht nicht so seekoffunbedingt Anwendungen fseek unter der Motorhaube. Vielmehr wird das (vermutlich vertraute?) Verhalten von fseekverwendet, um zu erklären, was zu seekofftun ist.
jjramsey
@jjramsey Das war auch mein Eindruck. Die Art und Weise, wie es formuliert ist, scheint jedoch eher eine Anforderung als eine Erklärung zu suggerieren.
Jceed2
1
@jjramsey Ich stimme zu, dass der Teil "Effekte" vernünftigerweise so interpretiert werden kann, dass er nicht wirklich aufgerufen fseekwerden muss, solange er etwas mit demselben Effekt tut. Da jedoch fseekein Versatz kleiner LONG_MINoder größer als LONG_MAXkeine Auswirkung hat, ist die Erklärung bestenfalls unvollständig, zumindest für Implementierungen, bei denen der streamoffAbstand breiter als ist long.
Keith Thompson

Antworten:

6

Ich denke, dass die Schlussfolgerung, dass Sie daraus ziehen, dass es eine Nichtübereinstimmung zwischen C ++ - Streams gibt und fseekdies zu Laufzeitfehlern führt, falsch ist. Die Situation scheint zu sein:

  1. Auf Systemen mit long64 Bit streamoffist definiert als longund die seekoffFunktion wird aufgerufen fseek.

  2. Auf Systemen mit long32 Bit, aber das Betriebssystem unterstützt 64-Bit-Datei-Offsets, streamoffist definiert als long longund seekoffruft eine Funktion auf, die entweder aufgerufen wird fseekooder fseeko64einen 64-Bit-Offset akzeptiert.

Hier ist ein Ausschnitt aus der Definition von seekoffauf meinem Linux-System:

#ifdef _GLIBCXX_USE_LFS
    if (!fseeko64(_M_file, __off, __whence))
      __ret = std::streampos(ftello64(_M_file));
#else
    if (!fseek(_M_file, __off, __whence))
      __ret = std::streampos(std::ftell(_M_file));
#endif

LFS steht für Large File Support .

Schlussfolgerung: Während der Standard eine Definition vorschlägt streamoff, die angeblich im Widerspruch zu der seekoffaufrufenden Anforderung steht, fseekverstehen Bibliotheksdesigner, dass sie die Variante aufrufen müssen fseek, die den gesamten Bereich der vom Betriebssystem unterstützten Offsets akzeptiert.

Willis Blackburn
quelle
@ypnos Ich habe nicht abgelehnt und finde diese Antwort hilfreich. Ich denke, jemand hat herabgestimmt, weil es den Punkt verfehlt. Das Problem ist nicht, dass es vernünftige Implementierungen gibt, die den Standard in dieser Hinsicht ignorieren. Das Problem ist, dass der Standard ignoriert werden muss, damit die Implementierung vernünftig ist.
Jceed2
6
The situation seems to be:- Die Situation ist , dass die Umsetzung nicht erlaubt ist , nicht zu nennen fseekin seekoff. Es muss anrufen fseek, nicht, Standard sagt, es muss. Ich kann argumentieren, dass diese Implementierung ungültig ist. Ich glaube, es beantwortet die Frage nicht. Och, fand llvm , es ruft fseeko.
KamilCuk
Genau wie zu Ihrer Information fordert VC ++ _fseeki64diese Funktion auf. das scheint auch zu verletzen, was der Standard sagt.
ChrisMM
1
Dies ist ein Fall, in dem die Implementierer das Problem erkennen und den Standard ignorieren. Ich bin froh, dass sie es getan haben, aber der Standard muss wirklich festgelegt werden.
NathanOliver
1
Einige Leute nehmen den Standard zu wörtlich. Es ist nicht erforderlich, dass die Implementierung buchstäblich eine aufgerufene Funktion aufruft fseek. An anderer Stelle beschreibt der Standard etwas als "wie durch einen Anruf fseek(...)". Wenn es so sehr darum ging, buchstäblich anzurufen fseek, wäre diese Aussage anders. Ernsthaft, was würden Sie tun, wenn Sie eine C ++ - Bibliothek implementieren würden? Würden Sie darauf bestehen, fseekmit den unteren 32 Bit eines 64-Bit-Dateiversatzes aufzurufen, weil Sie in einem Dokument dazu aufgefordert werden? Würden Ihre Kunden Ihnen dafür danken?
Willis Blackburn