Pourquoi le standard C ++ gère-t-il le fichier en cherchant comme il le fait?

17

C ++ utilise le streamofftype pour représenter un décalage dans un flux (de fichier) et est défini comme suit dans [stream.types]:

using streamoff = implementation-defined ;

Le type streamoff est synonyme de l'un des types intégraux de base signés de taille suffisante pour représenter la taille de fichier maximale possible pour le système d'exploitation. 287)

287) Typiquement longue et longue.

Cela a du sens, car il permet de rechercher dans des fichiers volumineux (par opposition à l'utilisation long, qui ne peut avoir qu'une largeur de 32 bits).

[filebuf.virtuals] définit basic_filebufla fonction de rechercher dans un fichier comme suit:

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

off_typeest équivalent à streamoff, voir [iostreams.limits.pos]. Cependant, la norme explique ensuite les effets de la fonction. Je suis irrité par la toute dernière phrase, qui nécessite un appel à fseek:

Effets : widthnotons a_codecvt.encoding(). Si is_open() == false, ou off != 0 && width <= 0, l'opération de positionnement échoue. Sinon, si way != basic_ios::curou off != 0, et si la dernière opération a été sortie, mettez à jour la séquence de sortie et écrivez toute séquence non décalée. Ensuite, recherchez la nouvelle position: si width > 0, appelez fseek(file, width * off, whence), sinon appelez fseek(file, 0, whence).

fseekaccepte un longparamètre. Si off_typeet streamoffsont définis comme long long(comme suggéré par la norme), cela pourrait conduire à une conversion vers le bas longlors de l'appel fseek(file, width * off, whence)(conduisant à des bogues potentiellement difficiles à diagnostiquer). Cela remet en question toute la justification de l'introduction du streamofftype en premier lieu.

Est-ce intentionnel ou un défaut dans la norme?

jceed2
la source
8
le défaut ressemble.
Yakk - Adam Nevraumont
Je pense que je vois que gcc libstdc ++ utilise fseeko64 .
KamilCuk
1
Offhand, il ne ressemble pas seekoffnécessairement à des utilisations fseek sous le capot. Le comportement (vraisemblablement familier?) De fseekest plutôt utilisé pour expliquer ce qui seekoffse passe.
jjramsey
@jjramsey C'était aussi mon impression. Cependant, la façon dont il est formulé semble suggérer une exigence plutôt qu'une explication.
jceed2
1
@jjramsey Je suis d'accord pour dire que la partie "Effets" peut raisonnablement être interprétée comme signifiant qu'elle n'a pas besoin d'appeler fseektant qu'elle fait quelque chose avec le même effet. Mais fseekavec un décalage inférieur LONG_MINou supérieur à LONG_MAXn'a aucun effet, donc l'explication est au mieux incomplète, au moins pour les implémentations où streamoffest plus large que long.
Keith Thompson

Réponses:

6

Je pense que la conclusion que vous tirez de cela, qu'il existe une incompatibilité entre les flux C ++ et fseekqui conduira à des bogues d'exécution, est incorrecte. La situation semble être:

  1. Sur les systèmes où longest 64 bits, streamoffest défini comme longet la seekofffonction appelle fseek.

  2. Sur les systèmes où longest 32 bits mais le système d'exploitation prend en charge les décalages de fichiers 64 bits, streamoffest défini comme long longet seekoffappelle une fonction appelée fseekoou fseeko64qui accepte un décalage 64 bits.

Voici un extrait de la définition de seekoffsur mon système 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 signifie Large File Support .

Conclusion: Bien que la norme suggère une définition pour streamoffcela en conflit ostensiblement avec l'exigence d' seekoffinvocation fseek, les concepteurs de bibliothèques comprennent qu'ils doivent appeler la variante fseekqui accepte la gamme complète de décalages pris en charge par le système d'exploitation.

Willis Blackburn
la source
@ypnos Je n'ai pas downvote et je trouve cette réponse utile. Je suppose que quelqu'un a voté contre parce qu'il manque le point. Le problème n'est pas qu'il existe des implémentations sensées qui ignorent la norme à cet égard, le problème est que la norme doit être ignorée pour que l'implémentation soit saine.
jceed2
6
The situation seems to be:- La situation est que la mise en œuvre n'a pas le droit de ne pas appeler fseekà seekoff. Il doit appeler fseek, ce n'est pas le cas, la norme dit qu'il doit le faire. Je peux affirmer que cette implémentation n'est pas valide. Je pense que cela ne répond pas à la question. Och, trouvé llvm , il appelle fseeko.
KamilCuk
Tout comme un FYI, VC ++ appelle _fseeki64cette fonction; qui semble également violer ce que dit la norme.
ChrisMM
1
Il s'agit d'un cas où les implémenteurs réalisent le problème et ignorent la norme. Je suis content qu'ils l'aient fait, mais la norme doit vraiment être fixée.
NathanOliver
1
Certaines personnes prennent la norme trop à la lettre. Il n'est pas exigeant que l'implémentation appelle littéralement une fonction appelée fseek. Ailleurs, la norme décrit quelque chose comme «comme si en appelant fseek(...)». Si cela tenait tant à appeler littéralement fseek, cette déclaration serait différente. Sérieusement, que feriez-vous si vous implémentiez une bibliothèque C ++? Souhaitez-vous insister pour appeler fseekavec les 32 bits inférieurs d'un décalage de fichier 64 bits, car un document vous le demande? Vos clients vous en remercieraient-ils?
Willis Blackburn