Буферизация ввода-вывода (IO buffering) присутствует в языке C с момента появления стандартной библиотеки (stdio). Она была введена для повышения производительности операций чтения и записи, поскольку обращения к диску или устройствам — дорогая операция по времени, и буферизация позволяет уменьшить их количество.
Непонимание работы буферизации может привести к неожиданным задержкам во вводе-выводе, потере данных при аварийном завершении программы, ошибкам в работе с несколькими потоками (особенно при stdout/stderr), а также к ошибкам синхронизации между процессами или системами.
Зная, что файловые потоки могут быть буферизированы, линейно буферизированы или небезапасно буферизированы, важно использовать функции принудительного сброса буфера (fflush()), корректно закрывать файлы (fclose()), а также грамотно комбинировать работу со stdin, stdout и stderr. Буферизация также зависит от типа потока (например, stdout сбрасывается при выводе символа в связанном с терминалом потоке, но не всегда — если это файл).
Пример кода:
#include <stdio.h> int main() { printf("Hello"); // sleep(10); // до fflush вывода не будет fflush(stdout); // сразу выводит буфер на экран return 0; }
Ключевые особенности:
fflush() — основной инструмент сброса буфера вручнуюМожно ли полагаться на то, что вывод printf сразу появится на экране?
Нет, если вывод идёт не в терминал, а например, в файл — строки не появятся до тех пор, пока не произойдёт flush буфера, либо не будет достигнут буферный лимит. Даже в терминале, строка без может не появиться сразу. Используйте fflush(stdout); для немедленного вывода.
Что произойдет, если вызвать fflush(stdin)?
Это undefined behavior согласно стандарту C. Некоторые компиляторы/платформы могут очищать буфер входного потока, но это не гарантируется стандартом, и такой приём не переносим и потенциально опасен.
Можно ли printf и fprintf(stderr, ...) считать эквивалентными для немедленного вывода?
Нет. Стандартный выход (stdout) обычно буферизуется полностью или построчно, stderr по стандарту всегда небезопасно буферизуется. То есть, вывод в stderr появляется на экране сразу, а в stdout — нет.
fflush(stdin) для очистки буфера вводаПрограмма пишет лог-файл через printf, но не вызывает fflush(stdout) и не закрывает файл при аварийном завершении.
Плюсы:
Минусы:
Программа после каждой важной лог-записи вызывает fflush(stdout), либо пишет критичные сообщения в stderr.
Плюсы:
Минусы: