在Windows CMD中运行程序时调整窗口大小致异常的解决问询
解决Windows CMD调整窗口尺寸导致C++程序异常/无限循环的问题
问题原因
Windows控制台在调整窗口大小或缓冲区尺寸时,会向关联进程发送WINDOW_BUFFER_SIZE_EVENT控制台事件。默认情况下,标准输入流std::cin会被该事件中断,导致std::cin.get()、getline()等输入函数返回失败(或触发EOF状态)。如果代码未处理这种错误状态,循环逻辑会反复执行,最终陷入无限循环。
解决方案1:注册控制台事件处理函数,忽略窗口尺寸变化事件
通过Windows API注册自定义控制台事件处理函数,过滤掉窗口尺寸变化事件,避免其干扰输入逻辑。同时在循环中处理std::cin的错误状态,确保输入流程正常恢复。
#include <iostream> #include <windows.h> #include <limits> // 用于std::numeric_limits // 自定义控制台事件处理函数 BOOL WINAPI ConsoleHandler(DWORD dwCtrlType) { if (dwCtrlType == WINDOW_BUFFER_SIZE_EVENT) { // 忽略窗口尺寸/缓冲区变化事件,返回TRUE表示已处理 return TRUE; } // 其他事件(如Ctrl+C)按系统默认逻辑处理 return FALSE; } int main() { // 注册事件处理函数 if (!SetConsoleCtrlHandler(ConsoleHandler, TRUE)) { std::cerr << "注册控制台事件处理器失败,错误码: " << GetLastError() << std::endl; return 1; } int i = 0; std::cout << "WHY!" << std::endl; do { // 清除之前可能触发的输入错误状态 if (!std::cin) { std::cin.clear(); // 忽略缓冲区中残留的无效数据 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); } std::cin.get(); std::cout << "This is working now\n"; ++i; } while (i < 10); return 0; }
解决方案2:使用Windows原生输入函数ReadConsole
改用Windows API提供的ReadConsole函数读取输入,该函数不会被窗口尺寸变化事件中断,能稳定处理控制台输入。缺点是代码会绑定Windows平台,失去跨平台兼容性。
#include <iostream> #include <windows.h> int main() { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE) { std::cerr << "获取标准输入句柄失败,错误码: " << GetLastError() << std::endl; return 1; } int i = 0; std::cout << "WHY!" << std::endl; do { wchar_t inputChar; DWORD charsRead; // 读取单个字符,不受窗口调整事件干扰 if (ReadConsole(hStdin, &inputChar, 1, &charsRead, NULL)) { std::cout << "This is working now\n"; ++i; } else { std::cerr << "读取输入失败,错误码: " << GetLastError() << std::endl; break; } } while (i < 10); return 0; }
注意事项
- 若使用CLion运行程序,需确保配置为在原生Windows CMD窗口中启动(而非CLion内置终端),两种方案才能正常生效。
- 方案1中,
std::numeric_limits需要包含<limits>头文件,否则会编译报错。
内容的提问来源于stack exchange,提问作者Nuno Domingues
相关产品推荐
相关产品推荐

