Почему printf не сбрасывается после вызова, если в строке формата не указана новая строка?

Почему printf не скрывается после вызова, если в строке формата не указана новая строка? Это поведение POSIX? Как я могу printf немедленно очищаться каждый раз?

+502
11 нояб. '09 в 16:22
источник поделиться
10 ответов

Поток stdout по умолчанию буферизован строкой, поэтому он будет отображать только то, что находится в буфере, после того, как он достигнет новой строки (или когда ему будет сказано). У вас есть несколько вариантов немедленной печати:

Напечатайте в stderr вместо этого, используя fprintf (stderr по умолчанию не буферизован):

fprintf(stderr, "I will be printed immediately");

Сбрасывайте стандартный вывод всякий раз, когда он вам нужен, используя fflush:

printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer

Изменить: из комментария Энди Росса, приведенного ниже, вы также можете отключить буферизацию на стандартном выводе с помощью setbuf:

setbuf(stdout, NULL);
+660
11 нояб. '09 в 17:04
источник

Нет, это не поведение 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.

+121
17 нояб. '10 в 3:52
источник
другие ответы

Связанные вопросы


Похожие вопросы

Вероятно, это из-за эффективности, и потому, что если у вас есть несколько программ, записывающих один 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

Обратите внимание, что даже не гарантируется сброс на новой строке, поэтому вы должны явно скрыться, если для вас есть вопросы.

+28
11 нояб. '09 в 17:54
источник

Для немедленного сброса вызова fflush(stdout) или fflush(NULL) (NULL означает сброс всего).

+24
11 нояб. '09 в 16:26
источник

Примечание. Библиотеки времени выполнения Microsoft не поддерживают буферизацию строк, поэтому printf("will print immediatelly to terminal"):

http://msdn.microsoft.com/en-us/library/86cebhfs.aspx

+15
26 окт. '10 в 20:47
источник

stdout буферизуется, поэтому будет выводиться только после печати новой строки.

Чтобы получить немедленный вывод, выполните следующие действия:

  • Печать в stderr.
  • Сделать stdout небуферизованным.
+11
11 нояб. '09 в 16:25
источник

по умолчанию, stdout является строковым буферизированным, stderr не имеет буферизации и файл полностью буферизирован.

+11
29 июл. '10 в 2:02
источник

Вы можете fprintf вместо stderr, который небуферизирован. Или вы можете сбросить stdout, когда захотите. Или вы можете установить stdout небуферизованным.

+10
11 нояб. '09 в 16:26
источник

Используйте setbuf(stdout, NULL); для отключения буферизации.

+9
31 мая '15 в 3:22
источник

Обычно есть 2 уровня buffering-

1. Кеш ядра буфера (ускоряет чтение/запись)

2. Буферизация в библиотеке ввода/вывода (уменьшает количество системных вызовов)

Давайте возьмем пример fprintf and write().

Когда вы вызываете fprintf(), он не записывается напрямую в файл. Сначала он идет в буфер stdio в памяти программы. Оттуда это записывается в буферный кеш ядра с помощью системного вызова write. Таким образом, один из способов пропустить буфер ввода-вывода - напрямую использовать write(). Другие способы - использование setbuff(stream,NULL). Это устанавливает режим буферизации на отсутствие буферизации, и данные напрямую записываются в буфер ядра. Чтобы принудительно переместить данные в буфер ядра, мы можем использовать "\n", который в случае режима буферизации по умолчанию "линейной буферизации" очистит буфер ввода-вывода. Или мы можем использовать fflush(FILE *stream).

Теперь мы находимся в буфере ядра. Ядро (/OS) хочет минимизировать время доступа к диску и, следовательно, читает/записывает только блоки диска. Поэтому, когда выдается read(), который является системным вызовом и может быть вызван напрямую или через fscanf(), ядро считывает блок диска с диска и сохраняет его в буфере. После этого данные копируются отсюда в пространство пользователя.

Аналогично, данные fprintf(), полученные из буфера ввода/вывода, записываются на диск ядром. Это делает read() write() быстрее.

Теперь, чтобы заставить ядро запустить write(), после чего передача данных контролируется аппаратными контроллерами, есть также несколько способов. Мы можем использовать O_SYNC или аналогичные флаги во время записи вызовов. Или мы могли бы использовать другие функции, такие как fsync(),fdatasync(),sync(), чтобы заставить ядро инициировать запись, как только данные будут доступны в буфере ядра.

+1
21 авг. '19 в 16:36
источник

Посмотрите другие вопросы по меткам или Задайте вопрос