题 “printf”在Windows非控制台应用程序中写入的位置?


如果我选择创建Windows非控制台应用程序,并实施 printf\cout 在代码中,哪里有 printf\cout 写?它是否写入 stdout 缓冲?如果是的话,无论如何都要阅读它 stdout 并将其打印到某个文本文件或执行 MessageBox 与文本(只是为了验证我已正确阅读)?

编辑:: 只是为了澄清我不想将输出重定向到任何地方。我想知道,在哪里 printf/cout 写?如果它写入某个默认缓冲区,有没有办法读取输出,只是为了验证我已经从正确的缓冲区读取了正确的输出。 请不要给我重定向“stdout”的解决方案


16
2018-02-08 13:33


起源


从技术上讲,它不会在任何地方写入,但您可以使用它将其重定向到文本文件 freopen("file.txt","w",stdout); - Predelnik
可能重复 如何将stdout重定向到Windows应用程序中的某些可见显示? - Martin R
@MartinR ::我不想重定向输出。我想知道,如果没有重定向,它写在哪里,有没有办法读取该位置进行验证。 - Abhineet
您可以阅读输出 nonconsole.exe | tee。 tee包含在“Git for Windows”中。 - elsamuko


答案:


在Windows下 stdout 是访问返回的句柄的低级函数的包装器 GetStdHandle(STD_OUTPUT_HANDLE)

通过双击启动非控制台应用程序(我尝试在Windows 7,64位下)然后 GetStdHandle(STD_OUTPUT_HANDLE) 将返回无效句柄。这意味着 printf 除了内部调用的低级函数之外,其他命令都不会写任何内容 printf 将返回错误代码。

但是,如前所述,即使是非控制台程序也可以通过以下方式启动:

program_name > output_file.txt

在这种情况下 printf 输出将写入输出文件。

- 编辑 -

如果你想“抓住” printf() 输出并写入 MessageBox() 有两种方法可以实现这一目标:

第一个是运行程序两次,而一个实例的输入是另一个实例的标准输出。可以通过以下命令行解释该行为:

program_name | program_name /msgbox

第二种可能性无需运行两个程序,也无需运行程序两次:您可以挂钩文件句柄#1。使用msvcrt.dll时至少应该这样:

HANDLE hRead,hWrite;

CreatePipe(&hRead,&hWrite,NULL,0);
dup2(_open_osfhandle(hWrite,O_WRONLY),1);

// Now printf() output can be read from handle hRead

printf("Hello world 2!\n");

// In a separate thread do:
ReadFile(hRead,...);

13
2018-02-09 11:34



+1远在此,您的解决方案看起来最适合我。 - Abhineet


由于您的问题似乎只是为了获取信息,因此没有控制台的Windows应用程序有stdout,stderr句柄已关闭。尝试输出到这些句柄的任何函数,只需调用,检查打开的句柄,找到它关闭,并返回而不做任何其他操作。

你可能会说,在这种情况下你的输出最终无处可寻:)

如果要读取此输出,则需要通过分配控制台或使用此处描述的方法之一来打开句柄。


10
2018-02-08 14:57





我正在开发一个可视化引擎,我使用以下两个东西来代替你在控制台应用程序中获得的pc和用户之间的标准输入/输出。

1:使用 sprintf  (int sprintf ( char * str, const char * format, ... ))。它的作用是打印成一个字符串而不是stdout(你不必使用临时文件)。在此之后你可以使用 MessageBox 用你刚刚打印到的字符串。

2:创建一个实际的控制台窗口(同时保持主窗口)并重定向 stdinstdout 和 stderr 从主窗口到控制台。这是一个建设课程:

ConsoleWindowClass.h:

 #pragma once
 #include <windows.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <io.h>
 #include <iostream>
 #include <fstream>
class ConsoleWindowClass
{
public:
    ConsoleWindowClass(void);
    ~ConsoleWindowClass(void);
    void Create();
};

ConsoleWindowClass.cpp:

 #include "ConsoleWindowClass.h"

using namespace std;

// maximum mumber of lines the output console should have
static const WORD MAX_CONSOLE_LINES = 500;

ConsoleWindowClass::ConsoleWindowClass(void)
{
    Create();
}

ConsoleWindowClass::~ConsoleWindowClass(void)
{
}

void ConsoleWindowClass::Create()
{
    int hConHandle;
    long lStdHandle;
    CONSOLE_SCREEN_BUFFER_INFO coninfo;
    FILE *fp;

// allocate a console for this app
    AllocConsole();

// set the screen buffer to be big enough to let us scroll text
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&coninfo);
    coninfo.dwSize.Y = MAX_CONSOLE_LINES;
    SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coninfo.dwSize);

// redirect unbuffered STDOUT to the console
    lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

    fp = _fdopen( hConHandle, "w" );

    *stdout = *fp;

    setvbuf( stdout, NULL, _IONBF, 0 );

// redirect unbuffered STDIN to the console

    lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

    fp = _fdopen( hConHandle, "r" );
    *stdin = *fp;
    setvbuf( stdin, NULL, _IONBF, 0 );

// redirect unbuffered STDERR to the console
    lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

    fp = _fdopen( hConHandle, "w" );

    *stderr = *fp;

    setvbuf( stderr, NULL, _IONBF, 0 );

// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
// point to console as well
    ios::sync_with_stdio();
}

在此之后,打电话 printf() 将字符串打印到控制台。您还可以使用控制台在其中键入字符串,并且可以从主窗口使用它们(使用多线程以便 scanf 不会暂停你的主程序)。


4
2018-02-08 13:53



如果你只想使用C而不是C ++,你可以删除<using namespace std>和ios :: sync_with_stdio()。你也必须在没有上课的情况下这样做。这是最后一行的作用: cplusplus.com/reference/ios/ios_base/sync_with_stdio - Vladivarius
感谢您的解决方案,但请阅读“编辑”。 - Abhineet
是的,在我写完答案后我理解了这个问题。无论如何,这将有望为寻找重定向的人服务:) - Vladivarius


printf 要么 cout 总是打印到 stdout

您需要从命令行启动程序并将其输出传递给文本文件以使其可读。

否则,您需要一个输出流到tmp中的文件,以便在代码中生成。

管道可以通过以下方式完成(如果您的应用程序名称为foo):

foo > log.txt

然后,您可以读取该文件 log.txt 如果您导航到其可以找到的目录

dir

2
2018-02-08 13:39



该声明 printf or cout always print to stdout是完全错的 - Dieter Lücking
他们正在打印到stdout,你必须重定向为调用者 - nesreka
@Dieter真的吗? “对象cout控制输出到与对象标准输出相关联的流缓冲区”(27.4.2 / 3) - Alan Stokes
的std :: cout.rdbuf(标准:: cerr.rdbuf());不会影响C层而是影响C ++层 - Dieter Lücking
感谢您的解决方案,但请阅读“编辑”。 - Abhineet