Что произойдет, если я не вызову fclose () в программе на C? - PullRequest
55 голосов
/ 18 ноября 2011

Во-первых, я знаю, что открывать файл с помощью fopen () и не закрывать его - ужасно безответственно и плохо. Это просто явное любопытство, так что, пожалуйста, позабавьте меня:)

Я знаю, что если программа на C открывает кучу файлов и никогда не закрывает ни один из них, в конечном итоге fopen () начнет работать с ошибкой. Есть ли другие побочные эффекты, которые могут вызвать проблемы вне самого кода? Например, если у меня есть программа, которая открывает один файл, а затем завершает работу, не закрывая его, может ли это вызвать проблемы у человека, выполняющего программу? Будет ли такая программа пропускать что-либо (память, файловые дескрипторы)? Могут ли быть проблемы с доступом к этому файлу после завершения программы? Что произойдет, если программа запускалась много раз подряд?

Ответы [ 4 ]

75 голосов
/ 18 ноября 2011

Пока ваша программа работает, если вы продолжаете открывать файлы, не закрывая их, наиболее вероятным результатом будет то, что у вас закончатся файловые дескрипторы / дескрипторы, доступные для вашего процесса, и попытка открыть больше файлов в конечном итоге потерпит неудачу. В Windows это также может помешать другим процессам открывать или удалять открытые вами файлы, поскольку по умолчанию файлы открываются в эксклюзивном режиме общего доступа, который не позволяет другим процессам открывать их.

После выхода из вашей программы операционная система очистится после вас. Он закроет все файлы, которые вы оставили открытыми, когда завершит ваш процесс, и выполнит любую другую необходимую очистку (например, если файл был помечен как delete-on-close, он затем удалит файл; обратите внимание, что такого рода вещи являются платформой -специфический).

Однако, еще одна проблема, о которой следует помнить, это буферизованные данные . Большинство файловых потоков буферизует данные в памяти перед их записью на диск. Если вы используете FILE* потоков из библиотеки stdio, то есть две возможности:

  1. Ваша программа завершилась нормально, либо вызвав функцию exit(3), либо вернувшись из main (который неявно вызывает exit(3)).
  2. Ваша программа вышла ненормально; это может быть вызвано abort(3) или _Exit(3), смертью от сигнала / исключения и т. д.

Если ваша программа завершилась нормально, среда выполнения C позаботится о сбросе всех буферизованных потоков, которые были открыты. Итак, если вы буферизовали данные, записанные в FILE*, который не был сброшен, он будет сброшен при нормальном выходе.

И наоборот, если ваша программа вышла ненормально, все буферизованные данные будут не сброшены. ОС просто говорит: «О, дорогой, вы оставили файловый дескриптор открытым, я лучше закрою его для вас», когда процесс завершится; он не знает, что где-то в памяти лежат случайные данные, которые программа намеревалась записать на диск, но не сделала этого. Так что будьте осторожны с этим.

13 голосов
/ 18 ноября 2011

Стандарт C говорит, что вызов exit (или, что то же самое, возвращение из main) приводит к тому, что все открытые FILE объекты закрываются, как если бы fclose.Так что это совершенно нормально, за исключением того, что вы лишены возможности обнаруживать ошибки записи.

РЕДАКТИРОВАТЬ: Нет такой гарантии для аварийного завершения (abort,неудачный assert, получение сигнала, поведение которого по умолчанию заключается в ненормальном завершении программы - обратите внимание, что таких сигналов не обязательно - и другие средства, определяемые реализацией).Как уже говорили другие, современные операционные системы будут очищать все видимые извне ресурсы, такие как открытые дескрипторы файлов на уровне ОС, независимо;однако, FILE s, вероятно, не будут сброшены в этом случае.

Конечно, были операционные системы, которые не очищали внешне видимые ресурсы при аварийном завершении;это имеет тенденцию идти вместе с неисполнением жестких границ привилегий между «ядром» и «пользовательским» кодом и / или между отдельными «процессами» пространства пользователя, просто потому, что если у вас нет этих границ, это может быть возможным чтобы сделать это безопасно во всех случаях.(Рассмотрим, например, что произойдет, если вы будете записывать мусор поверх таблицы открытых файлов в MS-DOS, как вы прекрасно умеете.)

5 голосов
/ 18 ноября 2011

Если вы выходите из-под контроля, используя системный вызов exit() или возвращаясь из main(), потоки открытых файлов закрываются после очистки. Стандарт C (и POSIX) предписывает это.

Если вы выйдете из-под контроля (дамп ядра, SIGKILL) и т. Д., Или если вы используете _exit() или _Exit(), то потоки открытых файлов не очищаются (но файловые дескрипторы заканчиваются закрыто, если предположить, что POSIX-подобная система с файловыми дескрипторами - стандарт C не требует файловых дескрипторов). Обратите внимание, что _Exit() предписан стандартом C99, но _exit() предписан POSIX (но они ведут себя одинаково в системах POSIX). Обратите внимание, что файловые дескрипторы отделены от файловых потоков. См. Обсуждение «Последствия завершения программы» на странице POSIX для _exit(), чтобы увидеть, что происходит, когда программа завершает работу в Unix.

0 голосов
/ 18 ноября 2011

Когда процесс умирает, большинство современных операционных систем (в частности, ядра) освобождают все ваши дескрипторы и выделенную память.

...