Why is the output order different from the call order when using fprintf with stdout or stderr?

My environment is Debian GNU/Linux 11.

The fprintf function with param stdout or stderr gives unexpected output order.

int main() {
    std::cout << "Hello, World!" << std::endl;
    fprintf(stderr, "22222\n");
    fprintf(stdout, "111\n");
    printf("3333 \n");
    printf("44444 \n");
    return 0;
}

I've run this many times and got many different results:

//①
22222
Hello, World!
111
3333 
44444

//②
Hello, World!
111
3333 
44444 
22222

What's the reason? Or, I want to understand the phenomenon, what knowledge do I need?

On my understanding, the output log should like this:

//③
Hello, World!
22222
111
3333 
44444 

About the two output logs of ①/②, I don't understand.

I think log ③ is right, but it does not appear, that makes me wonder.


The output is never like ② because output to stderr isn't buffered so 22222 will be flushed immediately and would be before any other numbers. Output to stdout may be line-buffered (default on Linux) or full-buffered (default on Windows)

The output shouldn't be like ① either because you're already flushing with std::endl in the first line, hence Hello, World! would be printed first. That's why never use std::endl unless you really know what it's doing. Always use std::cout << "Hello, World!\n";. See "std::endl" vs "\n"

③ should be the correct output because on Linux it'll flush on every statement, and on Windows the final 3 writes to stdout are flushed at once at the end

Hello, World!
22222
111
3333 
44444

If there are any differences then there are some issues with your stdlib

By default the legacy and C++ streams are also synchronized so it's possible to mix both types of streams with some performance penalty. You can disable it like this

std::ios::sync_with_stdio(false);

to get better performance but now the Hello, World! string can be printed anywhere