fclose
nécessite comme argument un FILE
pointeur obtenu soit par fopen
, l'un des flux standards stdin
, stdout
, ou stderr
, ou d'une autre manière définie par l'implémentation. Un pointeur nul n'en fait pas partie, donc le comportement n'est pas défini, tout comme fclose((FILE *)0xdeadbeef)
serait. NULL n'est pas spécial en C; mis à part le fait qu'il est garanti de ne pas être égal à n'importe quel pointeur valide, c'est comme n'importe quel autre pointeur invalide, et son utilisation invoque un comportement indéfini sauf lorsque l'interface que vous le transmettez aux documents dans le cadre de son contrat qui NULL
a une signification particulière.
De plus, revenir avec une erreur serait un comportement valide (puisque le comportement est indéfini de toute façon) mais nuisible pour une implémentation, car il cache le comportement indéfini . Le résultat préférable de l'appel d'un comportement indéfini est toujours un plantage, car il met en évidence l'erreur et vous permet de la corriger. La plupart des utilisateurs de fclose
ne vérifiez pas une valeur de retour d'erreur, et je parierais que la plupart des gens sont assez stupides pour passer NULL
à fclose
ne seront pas assez intelligents pour vérifier la valeur de retour de fclose
. Un argument pourrait être avancé que les gens devraient vérifier la valeur de retour de fclose
en général, car le vidage final peut échouer, mais ce n'est pas nécessaire pour les fichiers ouverts uniquement en lecture, ou si fflush
a été appelé manuellement avant fclose
(ce qui est de toute façon un idiome plus intelligent car il est plus facile de gérer l'erreur alors que le fichier est toujours ouvert).
fclose(NULL)
devrait réussir. free(NULL)
réussit, car cela facilite l'écriture du code de nettoyage.
Malheureusement, ce n'est pas ainsi qu'il a été défini. Par conséquent, vous ne pouvez pas utiliser fclose(NULL)
dans les programmes portables. (Par exemple, voir http://pubs.opengroup.org/onlinepubs/9699919799/).
Comme d'autres l'ont mentionné, vous ne voulez généralement pas de retour d'erreur si vous passez NULL au mauvais endroit. Vous voulez un message d'avertissement, au moins sur les versions de débogage/test. Le déréférencement NULL vous donne un message d'avertissement immédiat, et la possibilité de collecter une trace qui identifie l'erreur de programmation :). Pendant que vous programmez, une erreur de segmentation est la meilleure erreur que vous puissiez obtenir. C a beaucoup plus d'erreurs subtiles, qui prennent beaucoup plus de temps à déboguer...
Il est possible d'abuser des retours d'erreurs pour augmenter la robustesse contre les erreurs de programmation. Cependant, si vous craignez qu'un plantage logiciel ne perde des données, notez qu'exactement la même chose peut se produire, par ex. si votre matériel perd de la puissance. C'est pourquoi nous avons la sauvegarde automatique (depuis les éditeurs de texte Unix avec des noms à deux lettres comme ex et vi). Il serait toujours préférable que votre logiciel plante visiblement, plutôt que de continuer avec un état incohérent.
Les erreurs dont parle la page de manuel sont des erreurs d'exécution, pas des erreurs de programmation. Vous ne pouvez pas simplement passer NULL
dans n'importe quelle API attendant un pointeur et attendez-vous à ce que cette API fasse quelque chose de raisonnable. Passer un NULL
pointeur vers une fonction documentée pour exiger un pointeur vers des données est un bogue.
Question connexe :en C ou en C++, dois-je vérifier les paramètres de pointeur par rapport à NULL/nullptr ?
Pour citer le commentaire de R. sur l'une des réponses à cette question :
... vous semblez confondre les erreurs résultant de conditions exceptionnelles dans l'environnement d'exploitation (fs plein, mémoire insuffisante, réseau en panne, etc.) avec des erreurs de programmation. Dans le premier cas, bien sûr, un programme robuste doit être capable de les gérer avec élégance. Dans ce dernier cas, un programme robuste ne peut pas les expérimenter en premier lieu.