Где "printf" записывается в Windows-консольном приложении?

Если я решил создать неконфигурационное приложение Windows и реализовать printf\cout в коде, где пишет printf\cout? Записывает ли он буфер stdout? Если да, то все равно, чтобы прочитать его из stdout и распечатать его в каком-либо текстовом файле или сделать MessageBox с текстом (просто чтобы убедиться, что я прочитал его правильно)?

EDIT:: Просто чтобы уточнить, что я не хочу перенаправлять вывод в любом месте. Я хотел бы знать, где пишет printf/cout? И если он пишет в буфер по умолчанию, есть ли способ прочитать вывод, просто чтобы убедиться, что я прочитал правильный вывод и из правильного буфера. Пожалуйста, не давайте мне решений для перенаправления "stdout" .

Ответы

Ответ 1

В Windows stdout есть оболочка для низкоуровневых функций, обращающихся к дескриптору, возвращаемому GetStdHandle(STD_OUTPUT_HANDLE).

При запуске неконсольного приложения двойным щелчком (я попытался в Windows 7, 64 бит), тогда GetStdHandle(STD_OUTPUT_HANDLE) вернет недопустимый дескриптор. Это означает, что printf и другие команды ничего не будут писать, но низкоуровневые функции, вызванные внутри printf, возвращают код ошибки.

Однако, как уже говорилось, даже неконсольную программу можно запустить следующим образом:

program_name > output_file.txt

В этом случае вывод printf будет записан в выходной файл.

- EDIT -

Если вы хотите "поймать" вывод 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,...);

Ответ 2

Поскольку ваш вопрос, кажется, просто для информации, приложение Windows без консоли, имеет свои stdout, дескрипторы stderr закрыты. Любая функция, которая пытается вывести на эти дескрипторы, просто вызывается, проверяет открытый дескриптор, находит его закрытым и возвращается без каких-либо действий.

Вы можете сказать, что ваш результат в этом случае заканчивается нигде, чтобы быть найденным:)

Если вы хотите прочитать этот вывод, вам нужно открыть дескрипторы либо путем размещения консоли, либо с помощью одного из описанных здесь методов.

Ответ 3

Я разрабатываю визуальный движок, и я использую следующие две вещи в качестве замены стандартного ввода/вывода между ПК и пользователем, которые вы получаете в консольном приложении.

1: Используйте sprintf (int sprintf ( char * str, const char * format, ... )). То, что он делает, это печатать в строку вместо stdout (вам не нужно использовать временный файл). После этого вы можете использовать MessageBox со строкой, в которой вы только что напечатали.

2: создайте фактическое окно консоли (сохраняя основной) и перенаправьте stdin, stdout и 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

printf или cout всегда печатайте на stdout.

Вам нужно запустить программу из командной строки и передать ее вывод в текстовый файл, чтобы сделать его доступным для чтения.

В противном случае вам понадобится выходной поток для файла в tmp, который будет сгенерирован внутри вашего кода.

Трубопровод может быть выполнен следующим образом (если ваше имя приложения будет foo):

foo > log.txt

Затем вы можете прочитать файл log.txt, если перейти к его каталогу, который можно найти с помощью

dir