Quelle est la raison pour laquelle fread / fwrite prend la taille et compte comme arguments?

StackOverflow https://stackoverflow.com/questions/295994

  •  08-07-2019
  •  | 
  •  

Question

Au travail, nous avons discuté de la raison pour laquelle fread et fwrite prennent une taille par membre et comptent et renvoient le nombre de membres lus / écrits plutôt que de simplement prendre un tampon et une taille. La seule utilisation que nous pourrions en tirer est si vous voulez lire / écrire un tableau de structures qui ne sont pas divisibles de manière égale par l'alignement de la plate-forme et qui ont donc été complétées mais qui ne peuvent pas être assez communes pour justifier ce choix. dans la conception.

De FREAD (3) :

  

La fonction fread () lit nmemb éléments de données, chaque octet de taille long,   à partir du flux pointé par flux, en les stockant à l'emplacement indiqué   par ptr.

     

La fonction fwrite () écrit des éléments nmemb de données, chaque octet de taille.   long, au flux pointé par flux, les obtenant de l'emplacement   donné par ptr.

     

fread () et fwrite () renvoient le nombre d'éléments lus ou écrits avec succès   (c'est-à-dire pas le nombre de caractères). Si une erreur se produit, ou le   la fin du fichier est atteinte, la valeur renvoyée est un nombre d’articles court (ou zéro).

Était-ce utile?

La solution

Cela dépend de la manière dont fread est mis en œuvre.

La spécification Single UNIX indique

  

Pour chaque objet, les appels de taille doivent être   faite à la fonction fgetc () et à la   les résultats stockés, dans l’ordre de lecture, dans   un tableau de caractères non signés exactement   superposer l'objet.

fgetc a également cette note:

  

Puisque fgetc () fonctionne sur des octets,   lire un personnage composé de   plusieurs octets (ou "plusieurs octets"   caractère ") peut nécessiter plusieurs appels   fgetc ().

Bien sûr, cela est antérieur aux encodages de caractères sur octets de fantaisie comme UTF-8.

Le SUS note que cela provient en fait des documents ISO C.

Autres conseils

La différence entre fread (buf, 1000, 1, stream) et fread (buf, 1, 1000, stream) est que, dans le premier cas, vous n’obtenez qu’un bloc de 1000 octets ou nuthin, si le fichier est plus petit. et dans le second cas, vous obtenez tout dans le fichier moins de et jusqu'à 1000 octets.

C’est une pure spéculation, mais à l’époque (certains sont toujours là), de nombreux systèmes de fichiers ne sont pas de simples flux d’octets sur un disque dur.

De nombreux systèmes de fichiers étaient basés sur des enregistrements. Par conséquent, pour satisfaire ces systèmes de fichiers de manière efficace, vous devez spécifier le nombre d'éléments ("enregistrements"), ce qui permet à fwrite / fread de fonctionner sur le stockage en tant qu'enregistrements. juste des flux d'octets.

Ici, permettez-moi de corriger ces fonctions:

size_t fread_buf( void* ptr, size_t size, FILE* stream)
{
    return fread( ptr, 1, size, stream);
}


size_t fwrite_buf( void const* ptr, size_t size, FILE* stream)
{
    return fwrite( ptr, 1, size, stream);
}

Pour justifier les paramètres de fread () / fwrite () , j'ai perdu ma copie de K & amp; R il y a longtemps, donc je ne peux que deviner. . Je pense que la réponse probable est que Kernighan et Ritchie ont peut-être simplement pensé que l'exécution des E / S binaires se ferait le plus naturellement sur des tableaux d'objets. En outre, ils ont peut-être pensé que les E / S de bloc seraient plus rapides / plus faciles à implémenter ou autres sur certaines architectures.

Même si le standard C spécifie que fread () et fwrite () soient implémentés en termes de fgetc () et de fputc () , rappelez-vous que la norme est apparue longtemps après la définition de C par K & R et que les éléments spécifiés dans la norme n’étaient peut-être pas dans les idées originales du concepteur. Il est même possible que des choses dites dans K & amp; R "Langage de programmation C" peuvent ne pas être les mêmes que lors de la conception du langage.

Enfin, voici ce que P.J. Plauger a à dire à propos de fread () dans "La bibliothèque standard C":

  

Si l'argument size (seconde) est supérieur à un, vous ne pouvez pas déterminer   si la fonction a également lu jusqu'à taille - 1 caractères supplémentaires au-delà de ce qu'elle indique.   En règle générale, il est préférable d’appeler la fonction avec fread (buf, 1, taille * n, flux); au lieu de    fread (buf, taille, n, flux);

En gros, il dit que l'interface de fread () est cassée. Pour fwrite () , il note que "les erreurs d'écriture sont généralement rares, il ne s'agit donc pas d'une lacune majeure". - une déclaration avec laquelle je ne serais pas d'accord.

Cela revient probablement à la façon dont cette E / S de fichier a été implémentée. (retour dans la journée) Il aurait peut-être été plus rapide d’écrire / lire dans des fichiers en blocs que de tout écrire en même temps.

Je pense que c’est parce que C manque de surcharge de fonctions. S'il y en avait, la taille serait redondante. Mais en C, vous ne pouvez pas déterminer la taille d’un élément de tableau, vous devez en spécifier une.

Considérez ceci:

int intArray[10];
fwrite(intArray, sizeof(int), 10, fd);

Si vous écrivez le nombre d'octets accepté, vous pouvez écrire ce qui suit:

int intArray[10];
fwrite(intArray, sizeof(int)*10, fd);

Mais c'est juste inefficace. Vous aurez sizeof (int) fois plus d'appels système.

Un autre point à prendre en considération est que vous ne voulez généralement pas qu'une partie d'un élément de tableau soit écrite dans un fichier. Vous voulez l'entier entier ou rien. fwrite renvoie un certain nombre d'éléments écrits avec succès. Donc, si vous découvrez que seulement 2 octets de poids faible d’un élément sont écrits, que feriez-vous?

Sur certains systèmes (en raison de l'alignement), vous ne pouvez pas accéder à un octet de nombre entier sans créer de copie et de décalage.

Avoir des arguments distincts pour la taille et le nombre pourrait être avantageux pour une implémentation évitant la lecture d'enregistrements partiels. Si l'on devait utiliser des lectures sur un octet à partir de quelque chose comme un canal, même si on utilisait des données à format fixe, il faudrait prévoir la possibilité de séparer un enregistrement en deux lectures. If pourrait au contraire demander par exemple une lecture non bloquante de 40 enregistrements de 10 octets maximum quand il y a 293 octets disponibles et que le système renvoie 290 octets (29 enregistrements entiers) tout en laissant 3 octets prêts pour la lecture suivante, ce serait beaucoup plus pratique.

Je ne sais pas dans quelle mesure les implémentations de fread peuvent gérer une telle sémantique, mais elles pourraient certainement être utiles pour les implémentations qui pourraient promettre de les prendre en charge.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top