简体   繁体   English

fprintf和WriteConsole的输出顺序相反

[英]Output of fprintf and WriteConsole happen in reverse order

I'm seeing strange behavior with console I/O in Windows. 我在Windows中看到控制台I / O的奇怪行为。 When I open a FILE * using CONOUT$ as the path, it's supposed to open the console's stdout . 当我使用CONOUT$作为路径打开FILE * ,应该打开控制台的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. 如果我将该指针用于fprintf ,然后用于WriteConsole ,则您会认为消息会以各自的顺序出现,但实际上却是相反的。

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). 我的猜测与Win32 I / O功能和stdio同步(或者说不同步)有关。 I know C++ iostream needs to take special care to synchronize with stdio , so maybe Win32 doesn't do that? 我知道C ++ iostream需要特别注意才能与stdio同步,所以也许Win32不会这样做?

This might have to do with some buffering stdio.h adds to output. 这可能与stdio.h添加到输出中的某些缓冲有关。 Try adding a 尝试添加一个

fflush(fout);

after the fprintf . 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. 至于“奖金”( printf正常工作):Afaik stout通常以一种方式设置,即在每个换行符之后自动刷新。

It almost certainly has to do with stdio buffering, although in theory fout should not be fully-buffered. 尽管理论上不应完全缓冲fout ,但几乎可以肯定它与stdio缓冲有关。

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." C11§7.21.5.3/ 8:“当打开且仅当可以确定不引用交互式设备时,该流才被完全缓冲。该流的错误和文件结束指示符被清除。” 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. 因此,Windows stdio实现可能无法确定CONOUT$是交互式设备,但是标准的措辞似乎是,如果有疑问,则不应完全缓冲打开流。 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. 它可能是行缓冲打开的,但是在fprintf输出\\n ,所以在这种情况下应该没问题,实际上,使用printf可以证明这一点。

You could try using setvbuf to turn off buffering on fout and see if that helps. 您可以尝试使用setvbuf关闭fout缓冲,看看是否有帮助。

It is definitely the buffering of stdio getting in the way. 绝对是对stdio的阻碍。 I received the same output with both the MSVC2012 and mingw-w64 implementations. 我在MSVC2012和mingw-w64实现中都收到了相同的输出。

I decided to switch from the stdio layer to the POSIX layer, and the output was: 我决定从stdio层切换到POSIX层,输出为:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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