Obe*_*ane 30 c++ windows console
如果我有一个本机C++ Windows程序(即入口点是WinMain),我如何查看控制台函数的输出,如std :: cout?
luk*_*uke 22
查看将控制台I/O添加到Win32 GUI应用程序.这可以帮助您做您想做的事.
如果您没有或无法修改代码,请尝试此处找到的建议将控制台输出重定向到文件.
编辑:这里的线程坏死一点.我在第一次回答这个问题时,在早期的SO中,在非关联答案的(好)政策生效之前.我将重新发布原始文章中的代码,以期赎回我过去的罪过.
guicon.cpp - 控制台重定向功能
#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <fstream>
#ifndef _USE_OLD_IOSTREAMS
using namespace std;
#endif
// maximum mumber of lines the output console should have
static const WORD MAX_CONSOLE_LINES = 500;
#ifdef _DEBUG
void RedirectIOToConsole()
{
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();
}
#endif
//End of File
Run Code Online (Sandbox Code Playgroud)
guicon.h - 控制台重定向功能的接口
#ifndef __GUICON_H__
#define __GUICON_H__
#ifdef _DEBUG
void RedirectIOToConsole();
#endif
#endif
// End of File
Run Code Online (Sandbox Code Playgroud)
test.cpp - 演示控制台重定向
#include <windows.h>
#include <iostream>
#include <fstream>
#include <conio.h>
#include <stdio.h>
#ifndef _USE_OLD_OSTREAMS
using namespace std;
#endif
#include "guicon.h"
#include <crtdbg.h>
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
#ifdef _DEBUG
RedirectIOToConsole();
#endif
int iVar;
// test stdio
fprintf(stdout, "Test output to stdout\n");
fprintf(stderr, "Test output to stderr\n");
fprintf(stdout, "Enter an integer to test stdin: ");
scanf("%d", &iVar);
printf("You entered %d\n", iVar);
//test iostreams
cout << "Test output to cout" << endl;
cerr << "Test output to cerr" << endl;
clog << "Test output to clog" << endl;
cout << "Enter an integer to test cin: ";
cin >> iVar;
cout << "You entered " << iVar << endl;
#ifndef _USE_OLD_IOSTREAMS
// test wide iostreams
wcout << L"Test output to wcout" << endl;
wcerr << L"Test output to wcerr" << endl;
wclog << L"Test output to wclog" << endl;
wcout << L"Enter an integer to test wcin: ";
wcin >> iVar;
wcout << L"You entered " << iVar << endl;
#endif
// test CrtDbg output
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
_RPT0(_CRT_WARN, "This is testing _CRT_WARN output\n");
_RPT0(_CRT_ERROR, "This is testing _CRT_ERROR output\n");
_ASSERT( 0 && "testing _ASSERT" );
_ASSERTE( 0 && "testing _ASSERTE" );
Sleep(2000);
return 0;
}
//End of File
Run Code Online (Sandbox Code Playgroud)
Chr*_*sen 16
像luke和Sev这样的答案的问题在于,它们不必要地创建了新FILE
实例,然后这些实例会被泄露,并可能导致 CRT 清理代码中的调试断言。
freopen_s
真正需要的是:
FILE* fp = nullptr;
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
Run Code Online (Sandbox Code Playgroud)
您可能还想进行一些错误检查和清理。以下是我目前使用的完整解决方案。
重定向控制台标准 IO:
bool RedirectConsoleIO()
{
bool result = true;
FILE* fp;
// Redirect STDIN if the console has an input handle
if (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)
if (freopen_s(&fp, "CONIN$", "r", stdin) != 0)
result = false;
else
setvbuf(stdin, NULL, _IONBF, 0);
// Redirect STDOUT if the console has an output handle
if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE)
if (freopen_s(&fp, "CONOUT$", "w", stdout) != 0)
result = false;
else
setvbuf(stdout, NULL, _IONBF, 0);
// Redirect STDERR if the console has an error handle
if (GetStdHandle(STD_ERROR_HANDLE) != INVALID_HANDLE_VALUE)
if (freopen_s(&fp, "CONOUT$", "w", stderr) != 0)
result = false;
else
setvbuf(stderr, NULL, _IONBF, 0);
// Make C++ standard streams point to console as well.
ios::sync_with_stdio(true);
// Clear the error state for each of the C++ standard streams.
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
return result;
}
Run Code Online (Sandbox Code Playgroud)
释放控制台:
bool ReleaseConsole()
{
bool result = true;
FILE* fp;
// Just to be safe, redirect standard IO to NUL before releasing.
// Redirect STDIN to NUL
if (freopen_s(&fp, "NUL:", "r", stdin) != 0)
result = false;
else
setvbuf(stdin, NULL, _IONBF, 0);
// Redirect STDOUT to NUL
if (freopen_s(&fp, "NUL:", "w", stdout) != 0)
result = false;
else
setvbuf(stdout, NULL, _IONBF, 0);
// Redirect STDERR to NUL
if (freopen_s(&fp, "NUL:", "w", stderr) != 0)
result = false;
else
setvbuf(stderr, NULL, _IONBF, 0);
// Detach from console
if (!FreeConsole())
result = false;
return result;
}
Run Code Online (Sandbox Code Playgroud)
调整控制台缓冲区的大小:
void AdjustConsoleBuffer(int16_t minLength)
{
// Set the screen buffer to be big enough to scroll some text
CONSOLE_SCREEN_BUFFER_INFO conInfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo);
if (conInfo.dwSize.Y < minLength)
conInfo.dwSize.Y = minLength;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), conInfo.dwSize);
}
Run Code Online (Sandbox Code Playgroud)
分配一个新的控制台:
bool CreateNewConsole(int16_t minLength)
{
bool result = false;
// Release any current console and redirect IO to NUL
ReleaseConsole();
// Attempt to create new console
if (AllocConsole())
{
AdjustConsoleBuffer(minLength);
result = RedirectConsoleIO();
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
附加到家长的控制台:
bool AttachParentConsole(int16_t minLength)
{
bool result = false;
// Release any current console and redirect IO to NUL
ReleaseConsole();
// Attempt to attach to parent process's console
if (AttachConsole(ATTACH_PARENT_PROCESS))
{
AdjustConsoleBuffer(minLength);
result = RedirectConsoleIO();
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
从 WinMain 调用:
与 /SUBSYSTEM:Windows
int APIENTRY WinMain(
HINSTANCE /*hInstance*/,
HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/,
int /*cmdShow*/)
{
if (CreateNewConsole(1024))
{
int i;
// test stdio
fprintf(stdout, "Test output to stdout\n");
fprintf(stderr, "Test output to stderr\n");
fprintf(stdout, "Enter an integer to test stdin: ");
scanf("%d", &i);
printf("You entered %d\n", i);
// test iostreams
std::cout << "Test output to std::cout" << std::endl;
std::cerr << "Test output to std::cerr" << std::endl;
std::clog << "Test output to std::clog" << std::endl;
std::cout << "Enter an integer to test std::cin: ";
std::cin >> i;
std::cout << "You entered " << i << std::endl;
std::cout << endl << "Press any key to continue..." << endl;
_getch();
ReleaseConsole();
}
return 0;
};
Run Code Online (Sandbox Code Playgroud)
wor*_*ad3 10
您也可以重新打开cout和cerr流以输出到文件.以下应该适用于此:
#include <iostream>
#include <fstream>
int main ()
{
std::ofstream file;
file.open ("cout.txt");
std::streambuf* sbuf = std::cout.rdbuf();
std::cout.rdbuf(file.rdbuf());
//cout is now pointing to a file
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您将程序的输出发送到文件或管道,例如
myprogram.exe > file.txt
myprogram.exe | anotherprogram.exe
Run Code Online (Sandbox Code Playgroud)
或者您正在从另一个程序调用您的程序并通过管道捕获其输出,那么您不需要更改任何内容。即使入口点是WinMain
.
但是,如果您在控制台或 Visual Studio 中运行程序,则输出将不会出现在控制台或 Visual Studio 的“输出”窗口中。如果您想查看“实时”输出,请尝试其他答案之一。
基本上,这意味着标准输出就像控制台应用程序一样工作,但它没有连接到您运行应用程序的控制台,而且似乎没有简单的方法可以做到这一点(此处提供的所有其他解决方案都连接输出到一个新的控制台窗口,当你运行你的应用程序时会弹出这个窗口,即使是从另一个控制台)。
小智 8
实际上,有一个比迄今为止提出的任何解决方案都简单得多的解决方案。你的 Windows 程序将有一个 WinMain 函数,所以只需添加这个“虚拟”主函数
int main()
{
return WinMain(GetModuleHandle(NULL), NULL, GetCommandLineA(), SW_SHOWNORMAL);
}
Run Code Online (Sandbox Code Playgroud)
您现在可以像这样使用 MSVC 进行编译
cl /nologo /c /EHsc myprog.c
link /nologo /out:myprog.exe /subsystem:console myprog.obj user32.lib gdi32.lib
Run Code Online (Sandbox Code Playgroud)
(您可能需要添加更多库链接)
当您运行程序时,任何内容printf
都将写入命令提示符。
如果您使用 gcc (mingw) 为 Windows 编译,则不需要虚拟主函数,只需执行
gcc -o myprog.exe myprog.c -luser32 -lgdi32
Run Code Online (Sandbox Code Playgroud)
(即避免使用-mwindows
会阻止写入控制台的标志。当您创建最终的 GUI 版本时,该标志将很有用)如果使用更多的 Windows 功能,您可能需要指定更多的库)
小智 5
在Windows桌面应用程序项目中,结合使用luke的答案和Roger的答案对我有用。
void RedirectIOToConsole() {
//Create a console for this application
AllocConsole();
// Get STDOUT handle
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
int SystemOutput = _open_osfhandle(intptr_t(ConsoleOutput), _O_TEXT);
FILE *COutputHandle = _fdopen(SystemOutput, "w");
// Get STDERR handle
HANDLE ConsoleError = GetStdHandle(STD_ERROR_HANDLE);
int SystemError = _open_osfhandle(intptr_t(ConsoleError), _O_TEXT);
FILE *CErrorHandle = _fdopen(SystemError, "w");
// Get STDIN handle
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
int SystemInput = _open_osfhandle(intptr_t(ConsoleInput), _O_TEXT);
FILE *CInputHandle = _fdopen(SystemInput, "r");
//make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
ios::sync_with_stdio(true);
// Redirect the CRT standard input, output, and error handles to the console
freopen_s(&CInputHandle, "CONIN$", "r", stdin);
freopen_s(&COutputHandle, "CONOUT$", "w", stdout);
freopen_s(&CErrorHandle, "CONOUT$", "w", stderr);
//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 console or not.
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
}
Run Code Online (Sandbox Code Playgroud)
由于没有控制台窗口,所以这是不可能的困难。(每天学习新东西 - 我从来不知道控制台功能!)
您可以替换您的输出调用吗?我经常使用 TRACE 或 OutputDebugString 将信息发送到 Visual Studio 输出窗口。
归档时间: |
|
查看次数: |
73535 次 |
最近记录: |