Perché lo standard C ++ gestisce il file cercando il modo in cui lo fa?


17

C ++ utilizza il streamofftipo per rappresentare un offset all'interno di un flusso (file) ed è definito come segue in [stream.types]:

using streamoff = implementation-defined ;

Il tipo streamoff è sinonimo di uno dei tipi integrali di base firmati di dimensioni sufficienti per rappresentare la dimensione massima del file possibile per il sistema operativo. 287)

287) Tipicamente lungo lungo.

Questo ha senso perché consente di cercare all'interno di file di grandi dimensioni (anziché utilizzare long, che può essere largo solo 32 bit).

[filebuf.virtuals] definisce basic_filebufla funzione di ricerca all'interno di un file come segue:

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

off_typeè equivalente a streamoff, vedi [iostreams.limits.pos]. Tuttavia, lo standard prosegue spiegando gli effetti della funzione. Sono irritato dall'ultima frase, che richiede una chiamata a fseek:

Effetti : widthdenota a_codecvt.encoding(). Se is_open() == false, o off != 0 && width <= 0, l'operazione di posizionamento non riesce. Altrimenti, se way != basic_ios::curo off != 0e se è stata emessa l'ultima operazione, aggiornare la sequenza di emissione e scrivere qualsiasi sequenza non spostata. Quindi, cerca la nuova posizione: if width > 0, call fseek(file, width * off, whence), altrimenti call fseek(file, 0, whence).

fseekaccetta un longparametro Se off_typee streamoffsono definiti come long long(come suggerito dalla norma), ciò potrebbe comportare una conversione verso il basso longdurante la chiamata fseek(file, width * off, whence)(portando a bug potenzialmente difficili da diagnosticare). Ciò mette in discussione l'intera logica alla base dell'introduzione del streamofftipo.

Questo è intenzionale o un difetto nello standard?


8
il difetto sembra.
Yakk - Adam Nevraumont,

Penso di vedere che gcc libstdc ++ usa fseeko64 .
KamilCuk,

1
Di mano, non sembra seekoffnecessariamente usare fseek sotto il cofano. Piuttosto, il comportamento (presumibilmente familiare?) Di fseekviene usato per spiegare cosa seekoffsta facendo.
jjramsey,

@jjramsey Anche questa è stata la mia impressione. Tuttavia, il modo in cui è formulato sembra suggerire un requisito piuttosto che una spiegazione.
2

1
@jjramsey Sono d'accordo sul fatto che la parte "Effetti" possa ragionevolmente essere interpretata nel senso che non deve effettivamente chiamare fseekfinché fa qualcosa con lo stesso effetto. Ma fseekcon un offset minore LONG_MINo maggiore di LONG_MAXnon ha alcun effetto, quindi la spiegazione è nella migliore delle ipotesi incompleta, almeno per le implementazioni in cui streamoffè più ampio di long.
Keith Thompson,

Risposte:


6

Penso che la conclusione che stai prendendo da questo, che ci sia una discrepanza tra i flussi C ++ e fseekche porterà a bug di runtime, sia errata. La situazione sembra essere:

  1. Sui sistemi in cui longsono 64 bit, streamoffè definito come longe la seekofffunzione invoca fseek.

  2. Sui sistemi con long32 bit ma il sistema operativo supporta gli offset di file a 64 bit, streamoffviene definito come long longe seekoffrichiama una funzione denominata fseekoo fseeko64che accetta un offset a 64 bit.

Ecco lo snippet dalla definizione di seekoffsul mio sistema Linux:

#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 è l'acronimo di Large File Support .

Conclusione: mentre lo standard suggerisce una definizione streamoffche apparentemente è in conflitto con il requisito che seekoffinvocano fseek, i progettisti di biblioteche comprendono che devono chiamare la variante fseekche accetta l'intera gamma di offset supportati dal sistema operativo.


@ypnos Non ho votato in negativo e trovo utile questa risposta. Immagino che qualcuno abbia annullato il voto perché manca il punto. Il problema non è che ci sono implementazioni sane che ignorano lo standard in questo senso, il problema è che lo standard deve essere ignorato affinché l'implementazione sia sana.
2

6
The situation seems to be:- La situazione è che l'attuazione non è consentito di non chiamare fseekin seekoff. Deve chiamare fseek, non lo fa, lo standard dice che deve. Posso sostenere che questa implementazione non è valida. Credo che non risponda alla domanda. Och, trovato llvm , chiama fseeko.
KamilCuk,

Proprio come una FYI, VC ++ richiede _fseeki64questa funzione; che sembra anche violare ciò che dice lo standard.
ChrisMM,

1
Questo è il caso degli implementatori che comprendono il problema e ignorano lo standard. Sono contento che lo abbiano fatto, ma lo standard deve davvero essere risolto.
NathanOliver,

1
Alcune persone stanno prendendo lo standard troppo alla lettera. Non è impegnativo che l'implementazione chiami letteralmente una funzione chiamata fseek. Altrove lo standard descrive qualcosa come "come se chiamando fseek(...)". Se ci tenesse così tanto a chiamare letteralmente fseek, quell'affermazione sarebbe diversa. Scherzi a parte, cosa faresti se implementassi una libreria C ++? Insisteresti a chiamare fseekcon i 32 bit inferiori di un offset di file a 64 bit, perché un documento te lo dice? I tuoi clienti ti ringrazierebbero per questo?
Willis Blackburn,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.