Почему в этой программе функция printf
печатается или не печатается в зависимости от того, где она находится внутри цикла?
#include <stdio.h>
#include <time.h>
int main()
{
char frames[] = {'-', '\\', '|', '/'};
int i = 0;
time_t prev_time = time(0);
while(1) {
printf("\r%c", frames[i % 4]); //<- when placed here, it will flush
if (time(0) - prev_time < 1) continue;
//printf("\r%c", frames[i % 4]); <- when placed here, it needs to be manually flushed
//fflush(stdout);
prev_time = time(0);
i++;
}
return 0;
}
У вас уже есть лучший способ. Закомментируйте printf
перед if
и раскомментируйте printf/fflush
после него.
@CraigEstey В этом вопросе я описываю поведение своей программы. Я не спрашиваю, что мне «следует» делать. Когда строка помещается в начало цикла, она печатается, но когда строка помещается в середину цикла, она не печатается.
@CraigEstey, это потому, что цикл заставляет буфер заполняться 4096 байтами за одну секунду, поэтому он автоматически очищается?
Предложение: printf("\r%c", frames[i % 4]);
==> printf( "\r%c", "-\\|/"[ i & 3 ] );
(нет необходимости в frames[]
) и используйте счетчик unsigned
, который может легально переполняться без запуска UB...
@ Fe2O3 Как я уже сказал CraigEstey, меня не особо беспокоит правильная реализация этого. Это не проект, над которым я работаю. Я осознаю переполнение и все такое. Однако, несмотря на это, "-\\|/"[i & 3]
настолько безумно крут, что я все равно должен сказать вам спасибо. (Обратите внимание, я говорю о доступе к элементам из строкового литерала, а не об оптимизации по модулю. Я знаю об этом.) Это стандартное поведение C? Почему я никогда не видел этого раньше?
@user13456653 user13456653 Рад, что тебе это нравится. Предложение: посвятите час/день простому чтению кода других людей (здесь, на SO или на сайте SE-Code Review)... Хороший, плохой и ужасный... (Клинт Иствуд...) Ура! :-)
(PS: «Строковый литерал» — это неизменяемый «массив символов». Никакой настоящей магии здесь нет; просто еще одна идиома...)
Это поведение не конкретного printf
, а скорее выходного потока stdout
. Поток буферизуется и выдает выходные данные, когда происходит одно из следующих событий:
\n
(новая строка) (для интерактивного устройства),stdin
, а stdin
и stdout
относятся к одному и тому же интерактивному устройству.Обратите внимание: то, что представляет собой интерактивное устройство, определяется реализацией, поэтому, возможно, есть возможности для другого поведения.
В первом случае printf
будет вызываться много раз очень быстро и быстро заполнит буфер (и очистит его) блоками размером с буфер.
Во втором случае вывод буферизуется медленно. В конечном итоге он будет выведен, но для заполнения буфера потребуется значительно больше времени.
Если бы вы выполняли первый экземпляр построчно в отладчике, вы бы заметили, что результат тоже не будет немедленным.
Размер буфера зависит от реализации, но для буфера размером 4096 байт потребуется 34 минуты 8 секунд для заполнения и вывода данных.
Размещение новой строки в конце вывода — это обычный способ обеспечить немедленный вывод без сброса.
printf("%c\n", frames[i % 4]);
Выведет сразу куда угодно.
@Fe2O3 Я подозреваю, что все зависит от реализации/платформы, и я уверен, что могут быть другие способы, зависящие от реализации/платформы. Вышеупомянутое — это те утверждения, которые можно вывести из вопроса как истинные в данном случае. Когда стандартный ввод и стандартный вывод ссылаются на одно и то же «устройство», а стандартный ввод имеет локальное эхо-поведение, это, возможно, неизбежно, поскольку эхо передается на стандартный вывод и в результате сбрасывается. Это тот случай, когда в большинстве случаев оба ссылаются на консоль.
@ Fe2O3 Хорошая мысль. В этом вопросе нет комментариев, но я добавлю это. Кроме того, очистка новой строки гарантируется только для «интерактивного устройства». Это не обязательно должно происходить при перенаправлении в файл. То же самое, вероятно, справедливо и для сброса при вводе — они должны ссылаться на одно и то же интерактивное устройство, как я предполагал.
Время ПИТЫ... А вот и setvbuf()
быка за рога схватить... :-)
Ура!
Положение петли не имеет значения. По умолчанию
stdout
автоматически сбрасывается, когда видит\n
или когда буфер заполнен (это может быть 4096). Поскольку вы делаете\r
, вам следует делатьfflush
периодически. Для «сообщения о ходе выполнения» не реже одного раза в секунду. Самый простой — всегда делать это послеprintf
, но это может замедлить выполнение.