Обновлено февраль 2018 года:
Вот последняя версия функции, которая решает эту проблему:
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr)
{
// Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been
// observed that the file number of our standard handle file objects can be assigned internally to a value of -2
// when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our
// call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value
// before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to
// use the "nul" device, which will place them into a valid state, after which we can redirect them to our target
// using the "_dup2" function.
if (bindStdIn)
{
FILE* dummyFile;
freopen_s(&dummyFile, "nul", "r", stdin);
}
if (bindStdOut)
{
FILE* dummyFile;
freopen_s(&dummyFile, "nul", "w", stdout);
}
if (bindStdErr)
{
FILE* dummyFile;
freopen_s(&dummyFile, "nul", "w", stderr);
}
// Redirect unbuffered stdin from the current standard input handle
if (bindStdIn)
{
HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE);
if(stdHandle != INVALID_HANDLE_VALUE)
{
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
if(fileDescriptor != -1)
{
FILE* file = _fdopen(fileDescriptor, "r");
if(file != NULL)
{
int dup2Result = _dup2(_fileno(file), _fileno(stdin));
if (dup2Result == 0)
{
setvbuf(stdin, NULL, _IONBF, 0);
}
}
}
}
}
// Redirect unbuffered stdout to the current standard output handle
if (bindStdOut)
{
HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if(stdHandle != INVALID_HANDLE_VALUE)
{
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
if(fileDescriptor != -1)
{
FILE* file = _fdopen(fileDescriptor, "w");
if(file != NULL)
{
int dup2Result = _dup2(_fileno(file), _fileno(stdout));
if (dup2Result == 0)
{
setvbuf(stdout, NULL, _IONBF, 0);
}
}
}
}
}
// Redirect unbuffered stderr to the current standard error handle
if (bindStdErr)
{
HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);
if(stdHandle != INVALID_HANDLE_VALUE)
{
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
if(fileDescriptor != -1)
{
FILE* file = _fdopen(fileDescriptor, "w");
if(file != NULL)
{
int dup2Result = _dup2(_fileno(file), _fileno(stderr));
if (dup2Result == 0)
{
setvbuf(stderr, NULL, _IONBF, 0);
}
}
}
}
}
// Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the
// standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In
// versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything
// has been read from or written to the targets or not.
if (bindStdIn)
{
std::wcin.clear();
std::cin.clear();
}
if (bindStdOut)
{
std::wcout.clear();
std::cout.clear();
}
if (bindStdErr)
{
std::wcerr.clear();
std::cerr.clear();
}
}
Чтобы определить эту функцию, вам понадобится следующий набор включений:
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <iostream>
В двух словах, эта функция синхронизирует стандартные дескрипторы ввода / вывода / ошибки стандартной среды выполнения C / C ++ с текущими стандартными дескрипторами, связанными с процессом Win32. Как упоминалось в документации , AllocConsole изменяет эти дескрипторы процесса для нас, поэтому все, что требуется, это вызвать эту функцию после AllocConsole, чтобы обновить дескрипторы времени выполнения, в противном случае мы останемся с дескрипторами, которые были зафиксированы при время выполнения было инициализировано. Основное использование выглядит следующим образом:
// Allocate a console window for this process
AllocConsole();
// Update the C/C++ runtime standard input, output, and error targets to use the console window
BindCrtHandlesToStdHandles(true, true, true);
Эта функция прошла несколько ревизий, поэтому проверьте изменения этого ответа, если вас интересует историческая информация или альтернативы. Однако текущий ответ - лучшее решение этой проблемы, обеспечивающее большую гибкость и работающий с любой версией Visual Studio.