web-dev-qa-db-fra.com

Que se passe-t-il si je n'appelle pas fclose () dans un programme C?

Tout d'abord, je suis conscient que l'ouverture d'un fichier avec fopen () et sa fermeture est horriblement irresponsable et de mauvaise forme. C'est juste de la pure curiosité, alors s'il vous plaît, faites-moi plaisir :)

Je sais que si un programme C ouvre un tas de fichiers et n'en ferme aucun, fopen () finira par échouer. Y a-t-il d'autres effets secondaires qui pourraient causer des problèmes en dehors du code lui-même? Par exemple, si j'ai un programme qui ouvre un fichier, puis se ferme sans le fermer, cela pourrait-il causer un problème à la personne qui exécute le programme? Un tel programme aurait-il une fuite (mémoire, descripteurs de fichiers)? Pourrait-il y avoir des problèmes pour accéder à nouveau à ce fichier une fois le programme terminé? Que se passerait-il si le programme était exécuté plusieurs fois de suite?

56
electrodruid

Tant que votre programme est en cours d'exécution, si vous continuez à ouvrir des fichiers sans les fermer, le résultat le plus probable est que vous manquerez de descripteurs/poignées de fichiers disponibles pour votre processus, et la tentative d'ouvrir plus de fichiers échouera finalement. Sous Windows, cela peut également empêcher d'autres processus d'ouvrir ou de supprimer les fichiers que vous avez ouverts, car par défaut, les fichiers sont ouverts dans un mode de partage exclusif qui empêche d'autres processus de les ouvrir.

Une fois votre programme terminé, le système d'exploitation sera nettoyé après vous. Il fermera tous les fichiers que vous avez laissés ouverts à la fin de votre processus et effectuera tout autre nettoyage nécessaire (par exemple, si un fichier a été marqué comme supprimé à la fermeture, il supprimera alors le fichier; notez que ce genre de chose est une plate-forme -spécifique).

Cependant, un autre problème à prendre en compte est les données tamponnées . La plupart des flux de fichiers mettent en mémoire tampon les données en mémoire avant de les écrire sur le disque. Si vous utilisez des flux FILE* De la bibliothèque stdio, il y a deux possibilités:

  1. Votre programme s'est terminé normalement, soit en appelant la fonction exit(3) , soit en revenant de main (qui appelle implicitement exit(3)).
  2. Votre programme s'est arrêté anormalement; cela peut se faire en appelant abort(3) ou _Exit(3) , en mourant d'un signal/d'une exception, etc.

Si votre programme s'est terminé normalement, le runtime C se chargera de vider tous les flux mis en mémoire tampon qui étaient ouverts. Donc, si vous aviez des données tamponnées écrites dans un FILE* Qui n'ont pas été vidées, elles seront vidées à la sortie normale.

Inversement, si votre programme s'est arrêté anormalement, toutes les données mises en mémoire tampon seront pas vidées. Le système d'exploitation dit simplement "oh mon cher, vous avez laissé un descripteur de fichier ouvert, je ferais mieux de le fermer pour vous" lorsque le processus se termine; il n'a aucune idée qu'il existe des données aléatoires se trouvant quelque part dans la mémoire que le programme avait l'intention d'écrire sur le disque mais ne l'a pas fait. Soyez donc prudent à ce sujet.

76
Adam Rosenfield

La norme C indique que l'appel de exit (ou, de manière équivalente, le retour de main) entraîne la fermeture de tous les objets FILE ouverts comme par fclose. C'est donc parfaitement bien, sauf que vous perdez la possibilité de détecter les erreurs d'écriture.

EDIT: Il n'y a pas de telle garantie pour la terminaison anormale (abort, un échec assert, réception d'un signal dont le comportement par défaut est de terminer anormalement le programme - notez qu'il n'y a pas nécessairement de tels signaux - et d'autres moyens définis par l'implémentation). Comme d'autres l'ont dit, les systèmes d'exploitation modernes nettoieront toutes les ressources visibles de l'extérieur , telles que les descripteurs de fichiers ouverts au niveau du système d'exploitation; cependant, FILEs sont susceptibles et non d'être vidés dans ce cas.

Il y a certainement eu des systèmes d'exploitation qui n'ont pas nettoyé les ressources externes visibles en cas de terminaison anormale; il a tendance à ne pas imposer de limites de privilèges strictes entre le code "noyau" et "utilisateur" et/ou entre les "processus" d'espace utilisateur distincts, simplement parce que si vous n'avez pas ces limites, il se peut que ce ne soit pas le cas possible de le faire en toute sécurité dans tous les cas. (Considérez, par exemple, ce qui se passe si vous écrivez des ordures sur la table de fichiers ouverts dans MS-DOS, comme vous pouvez parfaitement le faire.)

13
zwol

En supposant que vous quittez sous contrôle, en utilisant l'appel système exit() ou en revenant de main(), les flux de fichiers ouverts sont fermés après le vidage. La norme C (et POSIX) l'exige.

Si vous quittez hors de contrôle (vidage de mémoire, SIGKILL), etc., ou si vous utilisez _exit() ou _Exit() , les flux de fichiers ouverts ne sont pas vidés ( mais les descripteurs de fichiers finissent fermés, en supposant un système de type POSIX avec des descripteurs de fichiers - la norme C n'impose pas les descripteurs de fichiers). Notez que _Exit() est mandaté par la norme C99, mais _exit() est mandaté par POSIX (mais ils se comportent de la même manière sur les systèmes POSIX). Notez que les descripteurs de fichiers sont distincts des flux de fichiers. Voir la discussion sur les "Conséquences de l'arrêt du programme" sur la page POSIX pour _exit() pour voir ce qui se passe lorsqu'un programme se termine sous Unix.

5
Jonathan Leffler

À la fin du processus, la plupart des systèmes d'exploitation modernes (le noyau en particulier) libéreront tous vos descripteurs et la mémoire allouée.

0
Peter