0

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.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Tom
  • 333
  • 2
  • 8
  • what do you mean by `the code only output like ② , but appear ①`? And there's no C/C++ language. `std::cout` doesn't exist in C – phuclv Jan 15 '22 at 03:49
  • Neat, but a great example of why you should not cross the streams. Even when fighting Gozer. – user4581301 Jan 15 '22 at 03:52
  • You notice that the “22222” is the only thing out of order, right? That is because you are printing that to a _different_ output stream than everything else, and there is no requirement that the two print in the same order as your output. Also notice that everything else is always in order? That is because `std::cout` is by default “tied” to the C standard output stream. If you break that connection, you may get even more random orderings. Chances are the reason has to do with when the streams get _flushed_. – Dúthomhas Jan 15 '22 at 04:05
  • If you want a specific order, make sure to flush the stream at the important points. Better yet, don’t mix output methods. – Dúthomhas Jan 15 '22 at 04:09

1 Answers1

2

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

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • @Tom what's cline? And you don't run g++ to get that output, you just use it to compile the program and then run the program – phuclv Jan 15 '22 at 04:37
  • 1. I use g++ compile main.cpp , and got a.out file , and then i run a.out got log ③ . 2. CLion is IDE , I use CLion run many times got output ① and ② 3. sorry i made a typo . – Tom Jan 15 '22 at 04:42
  • 1
    *"to get better performance ... "* in a a program making tens or hundreds or thousands of outputs... Good point to make, but very relative to use of I/O in the individual program. Not a scintilla of difference here. – David C. Rankin Jan 15 '22 at 06:22