2010-10-11 7 views
2

J'essaie d'apprendre C et le livre que j'utilise (Apress '' Learn C ') a un chapitre qui est terriblement déroutant sur les fonctions d'accès aléatoire. Le code suivant me confusion:Question de fonction d'accès aléatoire dans C

int GetNumberOfDinos(void) { 
    FILE *fp; 
    long fileLength; 

    if ((fp = fopen(kDinoFileName, "r")) == NULL) 
     DoError("Couldn't open file...Goodbye!"); 

    if (fseek(fp, 0L, SEEK_END) != 0) 
     DoError("Couldn't seek to end of file...Goodbye!"); 

    if ((fileLength = ftell(fp)) == -1L) 
     DoError("ftell() failed...Goodbye!"); 

    fclose(fp); 

    return((int)(fileLength/kDinoRecordSize)); 
} 

Je comprends le but du code, mais pas comment cet effet est atteint. La ligne fopen est facile à comprendre. Le fseek et ftell est où mes ennuis commencent. Les paramètres pour fseek sont le fichier, le décalage, puis l'un des 3 SEEK. Pourquoi la condition de cela n'est-elle pas nulle? Si le fichier existe réellement (kDinoFileName) et qu'il veut pointer vers la fin de ce fichier, pourquoi l'emplacement est-il nul? Le fichier existe et il y a des informations! Et puis je ne comprends absolument pas comment la fonction ftell finira jamais avec -1L ?? Ce code est-il plus difficile qu'il ne devrait l'être?

Répondre

5

Le code vérifie simplement les erreurs. fseek() renvoie 0 en cas de succès et non zéro en cas d'échec. ftell() renvoie -1 en cas d'échec.

Pour autant que "pourquoi l'emplacement serait-il nul?" - l'appel fseek() demande de rechercher à partir de la fin du fichier (SEEK_END). Zéro octets à partir de la fin du fichier est .. la fin du fichier. Donc

fseek(fp, 0L, SEEK_END) 

est une demande pour déplacer le pointeur de fichier à la fin du fichier.

Le code effectue les étapes suivantes:

  1. ouvrir le fichier
  2. cherchent à la fin
  3. obtenir la position du pointeur de fichier (qui, étant donné que nous sommes à la fin vous dit combien d'octets sont dans le fichier - note, strictement parlant le fichier doit être ouvert avec un accès binaire, par exemple en utilisant « rb », pour que cela soit vrai)

le code est quelque peu compliquée par l'erreur ha ndling. Beaucoup de livres et d'articles omettent la gestion des erreurs pour exactement cette raison. Cependant, cela a son propre inconvénient d'enseigner aux gens à ignorer les conditions d'erreur.

2

-1 peut se produire s'il existe une erreur inconnue, comme une erreur d'E/S essayant de lire le fichier. Vous constaterez que C utilise cette valeur spéciale -1, car elle ne dispose pas d'un véritable mécanisme d'exception comme le font les langages plus modernes, donc c'est juste une façon de dire, "hé, quelque chose de mal est arrivé ici".

Pour plus d'informations sur ftell, référez-vous à here.

"Si une erreur survient, -1L est renvoyé et la variable globale errno est définie sur une valeur positive Cette valeur peut être interprétée par perror."

+0

Il est important de noter que si un fseek échoue (par exemple en raison d'une erreur de lecture sur le support de disque), il n'y a aucune garantie quant à ce qu'un ftell() suivant sera renvoyé. Ce pourrait être un nombre qui est plausible mais faux. Si vous ne parvenez pas à détecter l'erreur sur fseek(), le programme risque d'utiliser une valeur de taille de fichier incorrecte sans avoir la moindre idée que c'est faux. – supercat

+0

@supercat - Mais si vous regardez le code affiché par l'OP, il vérifie la valeur de retour de fseek avant d'appeler ftell, donc je ne sais pas pourquoi votre commentaire "est important à noter". Si fseek échoue, l'appel à ftell n'aura jamais lieu dans son code, donc c'est vraiment un point discutable. Je suppose ici que sa fonction DoError effectue une sorte d'appel system.exit ou termine le programme d'une autre manière. – dcp

1

Ces conditions sont là juste comme une sauvegarde au cas où quelque chose de mal se passe. Même si vous savez que le fichier existe et que tous les paramètres sont corrects, un problème peut survenir avec le disque, par exemple. C'est toujours une bonne pratique de toujours vérifier les conditions d'erreur afin de ne pas continuer aveuglément à comprendre plus tard que quelque chose s'est mal passé.

0

fseek renvoie uniquement une indication de réussite ou d'échec, elle ne renvoie pas la position à laquelle le pointeur de fichier s'est arrêté. Il renvoie 0 en cas de succès, ce qui constitue le retour de succès standard pour de nombreuses fonctions de bibliothèque.

Dans le cas de ftell, il retournera la position actuelle du fichier du pointeur de fichier s'il n'y a pas d'erreur, donc un simple retour de 0 en cas de succès et différent de zéro en cas d'échec ne fonctionne pas. Ainsi, la fonction ftell renvoie -1 lorsqu'une défaillance se produit. C'est le retour d'erreur standard pour les fonctions qui renvoient un nombre qui a une signification.

Si vous regardez, le code se plaint d'une erreur quelconque lorsqu'une condition d'erreur se produit selon les informations que je viens de vous donner.

0

Les valeurs de retour pour les fonctions C standard peuvent parfois être étranges, car la plupart des fonctions renvoient un entier significatif et ne peuvent donc pas utiliser la même valeur de retour int pour indiquer une erreur.

Dans le cas de ftell, il renvoie le décalage actuel de votre pointeur de fichier. Si votre pointeur de fichier se trouve au début du fichier, il se trouve à l'offset 0. Par conséquent, 0 est un décalage valide et ne peut pas être utilisé pour indiquer une erreur. Donc, ils utilisent -1 à la place.

fseek est une instruction. Il pourrait revenir vide, mais ils décident de retourner quelque chose de plus significatif. En utilisant 0 pour le succès et non zéro pour l'échec, ils peuvent renvoyer différentes valeurs non nulles pour indiquer différentes erreurs. Incidemment, le code calcule la taille du fichier en allant à la fin, puis en demandant l'emplacement actuel. Vous le ferez parfois si vous voulez charger le fichier en mémoire et connaître le nombre d'octets à allouer.