Почему printf
не скрывается после вызова, если в строке формата не указана новая строка? Это поведение POSIX? Как я могу printf
немедленно очищаться каждый раз?
Поток stdout
буферизуется, поэтому будет отображаться только то, что в буфере после того, как оно достигнет новой строки (или когда оно было сказано). У вас есть несколько вариантов печати сразу:
Печать в stderr вместо этого с помощью fprintf
:
fprintf(stderr, "I will be printed immediately");
Сбрасывать stdout всякий раз, когда вам нужно использовать fflush
:
printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer
Изменить. Из комментария Энди Росса ниже вы также можете отключить буферизацию на stdout с помощью setbuf
:
setbuf(stdout, NULL);
setbuf(stdout, NULL);
Нет, это не поведение POSIX, это поведение ISO (ну, это поведение POSIX, но только постольку, поскольку они соответствуют ISO).
Стандартный вывод буферизируется по строке, если он может быть обнаружен для обращения к интерактивному устройству, иначе он полностью буферизуется. Таким образом, есть ситуации, когда printf
не будет скрываться, даже если он получает новую строку для отправки, например:
myprog >myfile.txt
Это имеет смысл для эффективности, поскольку, если вы взаимодействуете с пользователем, они, вероятно, хотят видеть каждую строку. Если вы отправляете вывод в файл, скорее всего, нет другого пользователя на другом конце (хотя это и не невозможно, они могут быть хвостом файла). Теперь вы можете утверждать, что пользователь хочет видеть каждого персонажа, но есть две проблемы с этим.
Во-первых, это не очень эффективно. Во-вторых, первоначальный мандат ANSI C заключался в том, чтобы в первую очередь кодифицировать существующее поведение, а не изобретать новое поведение, и эти проектные решения были приняты задолго до начала процесса ANSI. Даже ISO в настоящее время очень осторожно протекает при изменении существующих правил в стандартах.
Что касается того, как с этим бороться, если вы fflush (stdout)
после каждого выходного вызова, который хотите увидеть сразу, это решит проблему.
В качестве альтернативы вы можете использовать setvbuf
перед тем, как работать с stdout
, чтобы установить его на небуферизованный, и вам не придется беспокоиться о добавлении всех этих строк fflush
в ваш код:
setvbuf (stdout, NULL, _IONBF, BUFSIZ);
Просто имейте в виду, что это может сильно повлиять на производительность, если вы отправляете вывод в файл. Также имейте в виду, что поддержка для этого определяется реализацией, не гарантируемой стандартом.
Раздел ISO C99 7.19.3/3
- это соответствующий бит:
Когда поток небуферизован, символы должны появляться как из источника, так и в пункте назначения как можно скорее. В противном случае символы могут накапливаться и передаваться в или из среды хоста в виде блока.
Когда поток полностью буферизирован, символы предназначены для передачи в среду или из среды хоста в качестве блока при заполнении буфера.
Когда поток буферизуется в строке, символы предназначены для передачи в среду хоста или из нее как блок, когда встречается символ новой строки.
Кроме того, символы предназначены для передачи в виде блока в среду хоста при заполнении буфера, когда запрос запрашивается в небуферизованном потоке или когда запрос запрашивается в потоке с буферизацией, который требует передачи символов из среды хоста.
Поддержка этих характеристик определяется реализацией и может быть затронута с помощью функций
setbuf
иsetvbuf
.
myprog >/tmp/tmpfile
, это будет полностью буферизовано, а не буферизовано строкой. По памяти определение того, является ли ваш стандартный вывод интерактивным, оставлено на усмотрение реализации.
Вероятно, это из-за эффективности, и потому, что если у вас есть несколько программ, записывающих один TTY, таким образом вы не получите символов на чередующейся строке. Поэтому, если вы выдаете программы A и B, вы обычно получаете:
program A output
program B output
program B output
program A output
program B output
Это воняет, но это лучше, чем
proprogrgraam m AB ououtputputt
prproogrgram amB A ououtputtput
program B output
Обратите внимание, что даже не гарантируется сброс на новой строке, поэтому вы должны явно скрыться, если для вас есть вопросы.
Для немедленного сброса вызова fflush(stdout)
или fflush(NULL)
(NULL
означает сброс всего).
fflush(NULL);
обычно очень плохая идея. Это снизит производительность, если у вас будет открыто много файлов, особенно в многопоточной среде, где вы будете бороться со всеми за блокировки.
Примечание. Библиотеки времени выполнения Microsoft не поддерживают буферизацию строк, поэтому printf("will print immediatelly to terminal")
:
printf
идущий непосредственно к терминалу в «нормальном» случае, является тот факт, что printf
и fprintf
получают более грубую буферизацию даже в тех случаях, когда их вывод используется для немедленного использования. Если MS не исправит ошибки, одна программа не сможет захватить stderr и stdout из другой и определить, в какой последовательности они были отправлены.
по умолчанию, stdout является строковым буферизированным, stderr не имеет буферизации и файл полностью буферизирован.
stdout буферизуется, поэтому будет выводиться только после печати новой строки.
Чтобы получить немедленный вывод, выполните следующие действия:
fflush(stdout)
.
stderr
(этот ответ упоминается позже), fflush(stdout)
, fflush(NULL)
.
Вы можете fprintf вместо stderr, который небуферизирован. Или вы можете сбросить stdout, когда захотите. Или вы можете установить stdout небуферизованным.
Используйте setbuf(stdout, NULL);
для отключения буферизации.
setvbuf(stdout, (char*)NULL, _IONBF, 0)
решает эту проблему, но, конечно, не должно быть необходимым. Я использую MSVC ++ 2008 Express. ~~~