1

Why, in this program, does the printf function print or not print depending on where it is inside the loop?

#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;
}
7
  • Loop position doesn't matter. By default, stdout auto flushes when it sees \n or when the buffer is full (which could be 4096). Because you do \r, you should do fflush periodically. For a "progress message", at least once per second. The simplest is to always do it after your printf but this can slow execution. Commented Jul 13, 2024 at 3:36
  • You've already got the best way. Comment out the printf before the if and uncomment the printf/fflush after it. Commented Jul 13, 2024 at 3:41
  • 1
    @CraigEstey Im describing the behavior of my program in the question. I'm not asking what I "should" do. When the line is placed at the start of the loop it prints, but when placed in the middle of the loop it does not. Commented Jul 13, 2024 at 4:38
  • @CraigEstey is it because the loop causes the buffer to be filled up with 4096 bytes before one second passes so it flushes automatically? Commented Jul 13, 2024 at 4:40
  • Suggestion: printf("\r%c", frames[i % 4]); ==> printf( "\r%c", "-\\|/"[ i & 3 ] ); (no need for frames[]), and use an unsigned counter that can legally overflow without triggering UB... Commented Jul 13, 2024 at 7:10

1 Answer 1

2

It is not a behaviour of printf specifically, but rather of the stdout output stream. The stream is buffered and will emit output when one of the following occur:

  • a \n (newline) appears in the stream (for an interactive device),
  • the buffer becomes full,
  • the stream is explicitly flushed.
  • When input from stdin is requested and stdin and stdout refer to the same interactive device.

Note that what constitutes an interactive device is implementation-defined so there is scope for other behaviour perhaps.

In the first instance, printf will be called many times very quickly and will rapidly fill the buffer (so will flush) in buffer sized blocks.

In the second instance, the output is buffered slowly. It will eventually be output, but the buffer will take significantly more time to fill.

If you were to step the first instance line by line in your debugger, you will notice that the output for that is also not immediate.

The size of the buffer is implementation dependent, but for a 4096 byte buffer, it would take 34 minutes 8 seconds to fill and produce output.

Placing a newline at the end of the output is the usual way to ensure immediate output without a flush.

printf("%c\n", frames[i % 4]); 

Will output immediately anywhere.

Sign up to request clarification or add additional context in comments.

3 Comments

@Fe2O3 I suspect it is all implementation/platform dependent, and I am sure there may be other implementation/platform dependent ways. The above are those that can be inferred from the question to be true in this case. When stdin and stdout refer to the same "device", and stdin has local echo behaviour, it is perhaps inevitable, because the echo is to stdout, so is flushed as a result. That will be they case when the both refer to the console in most cases.
@Fe2O3 Good point. There is no input in this question, but I will add that. Also flushing on newline is only guaranteed for a "interactive device". It need not be case when redirected to a file. The same is probably true for flushing on input - they have to refer to the same interactive device I would imagine.
PITA-time... Then, there's setvbuf() to grab the bull by the horns... :-) Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.