简体   繁体   中英

Output of fprintf and WriteConsole happen in reverse order

I'm seeing strange behavior with console I/O in Windows. When I open a FILE * using CONOUT$ as the path, it's supposed to open the console's stdout . If I use that pointer for an fprintf and then a WriteConsole , you'd think the messages would come in respective order, but they actually happen in reverse.

Example code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <io.h>

int main(int argc, char *argv[]) {
  FILE *fout = fopen("CONOUT$", "w");
  fprintf(fout, "Hello world!\n");

  LPSTR goodbye = "Goodbye, cruel world!\n";
  DWORD length = strlen(goodbye);
  DWORD written;
  WriteConsole(_get_osfhandle(_fileno(fout)), goodbye, length, &written, NULL);

  return 0;
}

And the output:

Goodbye, cruel world!
Hello world!

Why is this? My guess is something to do with the way Win32 I/O functions and stdio synchronize (or rather, don't). I know C++ iostream needs to take special care to synchronize with stdio , so maybe Win32 doesn't do that?

This might have to do with some buffering stdio.h adds to output. Try adding a

fflush(fout);

after the fprintf . Alternatively you could try a

setbuf(fout, null);

to disable buffering for your output stream.

As to the "bonus" ( printf working correctly): Afaik stout is usually set up in a way that it flushes automatically after each newline.

It almost certainly has to do with stdio buffering, although in theory fout should not be fully-buffered.

C11 §7.21.5.3/8: "When opened, a stream is fully buffered if and only if it can be determined not to refer to an interactive device. The error and end-of-file indicators for the stream are cleared." So it may well not be possible for the Windows stdio implementation to determine that CONOUT$ is an interactive device, but the wording of standard seems to be that if there is doubt, the stream should not be opened fully-buffered. It might be opened line-buffered, but you output a \\n in the fprintf , so in that case you should be fine, and indeed that's more or less demonstrated by the fact that using printf works.

You could try using setvbuf to turn off buffering on fout and see if that helps.

It is definitely the buffering of stdio getting in the way. I received the same output with both the MSVC2012 and mingw-w64 implementations.

I decided to switch from the stdio layer to the POSIX layer, and the output was:

Hello world!
Goodbye, cruel world!

Your code, slightly modified:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <io.h> 
#include <fcntl.h>

int main(int argc, char *argv[]) {
  int fout = _open("CONOUT$", _O_WRONLY);
  char *hello = "Hello world!\n";
  _write(fout, hello, strlen (hello));

  LPSTR goodbye = "Goodbye, cruel world!\n";
  DWORD length = strlen(goodbye);
  DWORD written;
  WriteConsole(_get_osfhandle(fout), goodbye, length, &written, NULL);

  _close(fout);
  return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM