fprintf和WriteConsole的输出顺序相反

Output of fprintf and WriteConsole happen in reverse order

本文关键字:顺序 输出 WriteConsole fprintf      更新时间:2023-10-16

我在Windows中看到控制台I/O的奇怪行为。当我使用CONOUT$作为路径打开FILE *时,它应该打开控制台的stdout。如果我将该指针用于fprintf,然后用于WriteConsole,您会认为消息将按各自的顺序出现,但它们实际上是相反的。

示例代码:

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

输出:

Goodbye, cruel world!
Hello world!

为什么会这样?我的猜测与Win32 I/O函数和stdio同步的方式有关(或者更确切地说,不同步)。我知道C++iostream需要特别注意与stdio同步,所以Win32可能不能做到这一点?

这可能与stdio.h添加到输出中的一些缓冲有关。尝试添加

fflush(fout);

在CCD_ 10。或者你可以试试

setbuf(fout, null);

禁用输出流的缓冲。

至于"奖金"(printf工作正常):Afaik stout通常以在每一行换行后自动刷新的方式设置。

这几乎肯定与stdio缓冲有关,尽管理论上fout不应该完全缓冲。

C11§7.21.5.3/8:"当打开时,当且仅当可以确定流不是指交互式设备时,流才被完全缓冲。流的错误和文件结尾指示符被清除。"因此,Windows stdio实现可能不可能确定CONOUT$是交互式设备,但标准的措辞似乎是,如果有疑问,流不应该被完全缓冲地打开。它可能是开放的行缓冲的,但您在fprintf中输出了一个n,所以在这种情况下,您应该很好,事实上,使用printf或多或少可以证明这一点。

您可以尝试使用setvbuf关闭fout上的缓冲,看看这是否有帮助。

这肯定是stdio的缓冲。我在MSVC2012和mingw-w64实现中都收到了相同的输出。

我决定从stdio层切换到POSIX层,结果是:

Hello world!
Goodbye, cruel world!

您的代码,略有修改:

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