Was passiert, wenn ich fclose() in einem C-Programm nicht aufrufe?

Lesezeit: 6 Minuten

Erstens ist mir bewusst, dass das Öffnen einer Datei mit fopen() und das Nichtschließen schrecklich unverantwortlich und schlechte Form ist. Das ist nur reine Neugier, also bitte humor mich 🙂

Ich weiß, dass, wenn ein C-Programm eine Reihe von Dateien öffnet und keine davon schließt, fopen() irgendwann fehlschlägt. Gibt es andere Nebeneffekte, die Probleme außerhalb des Codes selbst verursachen könnten? Wenn ich zum Beispiel ein Programm habe, das eine Datei öffnet und dann beendet wird, ohne sie zu schließen, könnte das ein Problem für die Person verursachen, die das Programm ausführt? Würde ein solches Programm irgendetwas lecken (Speicher, Dateihandles)? Könnte es Probleme geben, auf diese Datei erneut zuzugreifen, nachdem das Programm beendet wurde? Was würde passieren, wenn das Programm viele Male hintereinander ausgeführt würde?

  • Keine Notwendigkeit für alle Haftungsausschlüsse. Es ist nichts Schlimmes daran, das Haus zu verlassen, ohne anzurufen fclosezumindest nicht mehr als die Verwendung goto. Es hängt alles von der Situation ab.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    18. November 2011 um 2:31 Uhr

Solange Ihr Programm ausgeführt wird und Sie weiterhin Dateien öffnen, ohne sie zu schließen, ist das wahrscheinlichste Ergebnis, dass Ihnen die für Ihren Prozess verfügbaren Dateideskriptoren/Handles ausgehen und der Versuch, weitere Dateien zu öffnen, schließlich fehlschlägt. Unter Windows kann dies auch verhindern, dass andere Prozesse die von Ihnen geöffneten Dateien öffnen oder löschen, da Dateien standardmäßig in einem exklusiven Freigabemodus geöffnet werden, der andere Prozesse daran hindert, sie zu öffnen.

Sobald Ihr Programm beendet wird, räumt das Betriebssystem nach Ihnen auf. Es wird alle Dateien schließen, die Sie offen gelassen haben, wenn es Ihren Prozess beendet, und alle anderen erforderlichen Aufräumarbeiten durchführen (z. B. wenn eine Datei als „Löschen beim Schließen“ markiert wurde, wird es die Datei dann löschen; beachten Sie, dass so etwas Plattform ist -Spezifisch).

Es gibt jedoch ein weiteres Problem, auf das Sie achten sollten gepufferte Daten. Die meisten Dateistreams puffern Daten im Arbeitsspeicher, bevor sie auf die Festplatte geschrieben werden. Wenn Sie verwenden FILE* Streams aus der stdio-Bibliothek, dann gibt es zwei Möglichkeiten:

  1. Ihr Programm wurde normal beendet, entweder durch Aufrufen der exit(3) Funktion oder durch Rückkehr von main (was implizit aufruft exit(3)).
  2. Ihr Programm wurde abnormal beendet; Dies kann per Anruf erfolgen abort(3) oder _Exit(3)Sterben aufgrund eines Signals/einer Ausnahme usw.

Wenn Ihr Programm normal beendet wurde, kümmert sich die C-Laufzeitumgebung darum, alle geöffneten gepufferten Streams zu leeren. Wenn Sie also gepufferte Daten in a geschrieben hätten FILE* das nicht gespült wurde, wird es beim normalen Beenden gespült.

Umgekehrt, wenn Ihr Programm abnormal beendet wurde, werden alle gepufferten Daten nicht gespült werden. Das Betriebssystem sagt nur “Oh mein Gott, Sie haben einen Dateideskriptor offen gelassen, ich schließe das besser für Sie”, wenn der Prozess beendet wird. es hat keine Ahnung, dass irgendwo im Speicher zufällige Daten liegen, die das Programm auf die Festplatte schreiben wollte, es aber nicht getan hat. Seien Sie also vorsichtig.

  • Irgendwelche Vermutungen darüber, wie lange dieser übrig gebliebene Puffer existieren würde, bevor er vom Betriebssystem wiedererlangt wird?

    – Benutzer10607

    15. Dezember 2014 um 12:46 Uhr

  • Ich würde so schnell wie möglich raten, da dieser Puffer nicht magisch ist – Ihr Programm hat ihm Speicher zugewiesen, und das Betriebssystem sollte diesen Speicher freigeben, wenn Ihr Programm im Rahmen der normalen Bereinigung abstürzt.

    – Xupicor

    7. Oktober 2016 um 23:07 Uhr

  • “[T]Das Betriebssystem wird nach Ihnen aufräumen” … Nun, das hängt wirklich vom Betriebssystem ab. Die wichtigsten Desktop-Betriebssysteme werden das tun, aber es ist nicht garantiert.

    – Irgendein Programmierer-Typ

    17. September 2019 um 6:18 Uhr

Benutzeravatar von twol
zwöl

Der C-Standard sagt diese Berufung exit (oder gleichwertig zurückkehren von main) bewirkt, dass alle offen sind FILE Objekte, die als ob von geschlossen werden sollen fclose. Das ist also völlig in Ordnung, außer dass Sie die Möglichkeit verlieren, Schreibfehler zu erkennen.

BEARBEITEN: Eine solche Garantie gibt es nicht abnormal Beendigung (abortein Fehlschlag assert, Empfang eines Signals, dessen Standardverhalten darin besteht, das Programm abnormal zu beenden – beachten Sie, dass es nicht unbedingt solche Signale gibt – und andere implementierungsdefinierte Mittel). Wie andere gesagt haben, werden moderne Betriebssysteme alles bereinigen äußerlich sichtbar Ressourcen wie offene Dateihandles auf Betriebssystemebene, unabhängig davon; jedoch, FILEs sind wahrscheinlich nicht in diesem Fall gespült werden.

Es hat sicherlich Betriebssysteme gegeben, die extern sichtbare Ressourcen bei abnormaler Beendigung nicht bereinigt haben; Es neigt dazu, keine harten Privilegiengrenzen zwischen “Kernel” – und “Benutzer” -Code und / oder zwischen verschiedenen “Prozessen” des Benutzerbereichs durchzusetzen, einfach weil, wenn Sie diese Grenzen nicht haben, dies möglicherweise nicht der Fall ist möglich um dies in allen Fällen sicher zu tun. (Überlegen Sie zum Beispiel, was passiert, wenn Sie in MS-DOS Datenmüll über die Open-File-Tabelle schreiben, wozu Sie durchaus in der Lage sind.)

  • Könnten Sie eine Referenz angeben, warum sollte dies nicht betriebssystemspezifisch sein?

    – Petrus

    17. November 2011 um 23:46 Uhr

  • @Peter: C99, §7.20.4.3, ¶ 4: “Als nächstes werden alle offenen Streams mit ungeschriebenen gepufferten Daten geleert, alle offenen Streams geschlossen und alle von der tmpfile-Funktion erstellten Dateien entfernt.” Beachten Sie, dass dies nur für normale (exit, return aus main) Kündigung, was passiert mit _Exit & co. ist implementierungsdefiniert.

    – Matteo Italien

    17. November 2011 um 23:48 Uhr

  • @MatteoItalia, danke, aber es stimmt auch, dass die meisten modernen Betriebssysteme die Handles und den Speicher trotzdem bereinigen, wenn der Prozess aus einem anderen Grund unerwartet beendet wird.

    – Petrus

    17. November 2011 um 23:57 Uhr

  • @Peter: sicher, aber da Sie einen betriebssystemunabhängigen Hinweis auf diese Tatsache wollten, habe ich ihn bereitgestellt nur die durch die Norm gegebenen Garantien. 🙂

    – Matteo Italien

    17. November 2011 um 23:59 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Unter der Annahme, dass Sie den Ausgang unter Kontrolle haben, verwenden Sie die exit() Systemaufruf oder Rückkehr von main(), dann werden die offenen Dateiströme nach dem Leeren geschlossen. Der C-Standard (und POSIX) schreibt dies vor.

Wenn Sie außer Kontrolle geraten (Core Dump, SIGKILL) usw. oder wenn Sie verwenden _exit() oder _Exit(), dann werden die offenen Dateiströme nicht geleert (aber die Dateideskriptoren werden geschlossen, vorausgesetzt, ein POSIX-ähnliches System mit Dateideskriptoren – Standard C schreibt keine Dateideskriptoren vor). Beachten Sie, dass _Exit() wird vom C99-Standard vorgeschrieben, aber _exit() wird von POSIX vorgeschrieben (aber sie verhalten sich auf POSIX-Systemen gleich). Beachten Sie, dass Dateideskriptoren von Dateiströmen getrennt sind. Siehe die Diskussion von ‘Folgen der Programmbeendigung’ auf der POSIX-Seite für _exit() um zu sehen, was passiert, wenn ein Programm unter Unix beendet wird.

  • “aber die Dateideskriptoren werden geschlossen” – sind Sie sicher? Der Standard besagt: „Ob offene Streams mit ungeschriebenen gepufferten Daten geleert, offene Streams geschlossen oder temporäre Dateien entfernt werden, ist implementierungsdefiniert.“ (C99 §7.20.4.4 Abs. 2)

    – Matteo Italien

    17. November 2011 um 23:47 Uhr


  • Die Streams sind nicht geschlossen; die Dateideskriptoren sind. Es gibt einen (großen) Unterschied. Alle Dateideskriptoren werden geschlossen, wenn ein Programm beendet wird – siehe ‘Folgen der Programmbeendigung’ auf der _Exit() Seitenverweis Ich gehe davon aus, dass das System eine POSIX-ähnliche Semantik bietet; in reinem Standard-C gibt es keine Dateideskriptoren. Das Verhalten für Nicht-POSIX-Systeme kann etwas anders sein.

    – Jonathan Leffler

    17. November 2011 um 23:48 Uhr


  • Das ist, was ich sage: Was den C-Standard betrifft, was passiert auf _Exit() ist implementierungsdefiniert (und eines dieser möglichen Verhaltensweisen ist das vom POSIX-Standard vorgeschriebene).

    – Matteo Italien

    17. November 2011 um 23:52 Uhr

Benutzeravatar von Peter
Peter

Wenn der Prozess stirbt, geben die meisten modernen Betriebssysteme (insbesondere der Kernel) alle Ihre Handles und den zugewiesenen Speicher frei.

1418050cookie-checkWas passiert, wenn ich fclose() in einem C-Programm nicht aufrufe?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy