3

On Windows, I observe that if the output is redirected from the console to a file, then mixing calls to printf and Windows' WriteFile will result in the data being written to the file in a different order than the calls appeared in the code. Fair enough. That's understandable.

However, I've so far observed that when the output is directed to the console and I mix calls to printf and Windows' WriteConsole the data is always printed in the same order as the calls.

Is this latter behaviour guaranteed? Can I rely on it or are there situations where this order might change also?

Here's an example:

#include <stdio.h>
#include <windows.h>

int main() {
    DWORD lpMode;
    DWORD dwCount;
    HANDLE winout = GetStdHandle(STD_OUTPUT_HANDLE);
    BOOL is_console = GetConsoleMode(winout, &lpMode);
    if (is_console) {
        printf("Line 1 to console using printf.\n");
        WriteConsoleA(winout, "Line 2 to console using WriteConsoleA.\n", 39, &dwCount, NULL);
        printf("Line 3 to console using printf.\n");
        WriteConsoleA(winout, "Line 4 to console using WriteConsoleA.\n", 39, &dwCount, NULL);
        printf("Line 5 to console using printf.\n");
        WriteConsoleA(winout, "Line 6 to console using WriteConsoleA.\n", 39, &dwCount, NULL);
        printf("Line 7 to console using printf.\n");
        WriteConsoleA(winout, "Line 8 to console using WriteConsoleA.\n", 39, &dwCount, NULL);
    } else {
        printf("Line 1 to file using printf.\n");
        WriteFile(winout, "Line 2 to file using WriteFile.\n", 32, &dwCount, NULL);
        printf("Line 3 to file using printf.\n");
        WriteFile(winout, "Line 4 to file using WriteFile.\n", 32, &dwCount, NULL);
        printf("Line 5 to file using printf.\n");
        WriteFile(winout, "Line 6 to file using WriteFile.\n", 32, &dwCount, NULL);
        printf("Line 7 to file using printf.\n");
        WriteFile(winout, "Line 8 to file using WriteFile.\n", 32, &dwCount, NULL);
    }
    return 0;
}

When the output is redirected to a file, the file contains:

Line 2 to file using WriteFile.
Line 4 to file using WriteFile.
Line 6 to file using WriteFile.
Line 8 to file using WriteFile.
Line 1 to file using printf.
Line 3 to file using printf.
Line 5 to file using printf.
Line 7 to file using printf.

When the output is directed to the console, the following is printed:

Line 1 to console using printf.
Line 2 to console using WriteConsoleA.
Line 3 to console using printf.
Line 4 to console using WriteConsoleA.
Line 5 to console using printf.
Line 6 to console using WriteConsoleA.
Line 7 to console using printf.
Line 8 to console using WriteConsoleA.

To be clear, I'm not asking about WriteFile here. My question is not about why the first set of output to the file is in the “incorrect” order, but rather why the second set of output to the console is in the “correct” order, and when (if ever) this behaviour cannot be assumed for WriteConsole.

WiseGenius
  • 226
  • 2
  • 9
  • 1
    *Can I rely on it* - for what you need rely on it ? – RbMm Jan 24 '21 at 13:59
  • 1
    No, that behavior isn't guaranteed. `WriteConsole` doesn't know about `printf`, so it cannot possibly synchronize with it. If strict sequencing happens, that's just an implementation detail of the `printf` implementation. Or an accident. – IInspectable Jan 24 '21 at 15:24
  • How to mix calls to printf and Windows' WriteConsole? Please show some codes. Note:`WriteConsole` fails if it is used with a standard handle that is redirected to a file. Have you tried mixing `WriteFile` and `printf` when the output is directed to the console instead of a file? – Strive Sun Jan 25 '21 at 02:01
  • It is a runtime implementation detail, practically all of them do this. When stdout is redirected then [it is buffered](https://stackoverflow.com/questions/39536212/what-are-the-rules-of-automatic-stdout-buffer-flushing-in-c), WriteConsole is not. So if you mix then you'll have to flush stdout yourself. – Hans Passant Jan 25 '21 at 05:04

2 Answers2

1

You are never going to get guaranteed behavior here because mixing raw Win32 API and the C API is probably not a supported scenario.

Calling fflush after printf is probably going to fix it for you but the best option is to not mix different APIs. To be really sure you might want to call FlushFileBuffers after WriteFile as well but that might degrade performance too much if you write a lot of data.

If you can't add fflush calls, another alternative you can try is _open_osfhandle + dup2 to replace stdout and then call setbuf/setvbuf to disable buffering.

The console does not use files, older versions of Windows use a synchronous API to communicate with another process (csrss or conhost) and newer versions use IOCTLs. WriteFile has a special hook that uses this other API if the file handle is the console.

Anders
  • 97,548
  • 12
  • 110
  • 164
0

My question is not about why the first set of output to the file is in the “incorrect” order, but rather why the second set of output to the console is in the “correct” order, and when (if ever) this behaviour cannot be assumed for WriteConsole.

In fact, when the output is directed to the console, whether you use WriteConsoleA or WriteFile, it will print sequentially.

The only difference is whether the console is redirected to a file.

When we redirect to a file, the stream is fully buffered and will not be flushed except with fflush(), unless you write gobloads of data to it.

Flushing for stdout is determined by its buffering behaviour. The buffering can be set to three modes: _IOFBF (full buffering: waits until fflush() if possible), _IOLBF (line buffering: newline triggers automatic flush), and _IONBF (direct write always used). "Support for these characteristics is implementation-defined, and may be affected via the setbuf() and setvbuf() functions." [C99:7.19.3.3]

Refer this link for more information.

Strive Sun
  • 5,988
  • 1
  • 9
  • 26