Windows 下用 GetConsoleScreenBufferInfo 可靠获取控制台行列数;Linux/macOS 下应读取 ioctl 的 TIOCGWINSZ,不能依赖环境变量或 stty 命令。

Windows 下用 GetConsoleScreenBufferInfo 可靠获取控制台行列数;Linux/macOS 下应读取 ioctl 的 TIOCGWINSZ,不能依赖环境变量或 stty 命令。
Windows:用 GetConsoleScreenBufferInfo 获取真实尺寸
这是 Windows API 中唯一能准确返回当前控制台窗口缓冲区宽高(字符单位)的函数。注意它返回的是缓冲区大小,不是窗口可视区域——但绝大多数情况下二者一致,除非启用了滚动条且缓冲区远大于窗口。
关键点:
-
GetStdHandle(STD_OUTPUT_HANDLE)必须成功,重定向时可能失效(如管道或文件输出) -
CONSOLE_SCREEN_BUFFER_INFO中的srWindow是可视区域,dwSize是整个缓冲区;推荐用srWindow的宽高 - 列数 =
info.srWindow.Right - info.srWindow.Left + 1,行数 =info.srWindow.Bottom - info.srWindow.Top + 1
#include#include bool getConsoleSize(int& cols, int& rows) { CONSOLE_SCREEN_BUFFER_INFO info; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); if (hOut == INVALID_HANDLE_VALUE) return false; if (!GetConsoleScreenBufferInfo(hOut, &info)) return false; cols = info.srWindow.Right - info.srWindow.Left + 1; rows = info.srWindow.Bottom - info.srWindow.Top + 1; return true; }
Linux/macOS:用 ioctl 调用 TIOCGWINSZ
POSIX 系统没有统一的“控制台大小 API”,ioctl 是标准且最可靠的方式。它直接向终端设备查询当前窗口尺寸,不受 shell 类型或重定向影响(只要 stdout 是 tty)。
立即学习“C++免费学习笔记(深入)”;
常见误区:
- 读取
$COLUMNS/$LINES环境变量——它们可能未设置、过期或被用户手动修改 - 调用
stty size并解析输出——启动子进程开销大,且在容器或精简环境中可能不可用 - 假设
stdin和stdout尺寸一致——实际中可能不同(尤其重定向后)
#include#include #include bool getConsoleSize(int& cols, int& rows) { struct winsize w; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == -1) return false; cols = w.ws_col; rows = w.ws_row; return true; }
跨平台封装需注意的兼容性陷阱
同一份代码在 Windows/Linux 上编译时,头文件、函数名、宏定义完全不同,简单 #ifdef 容易漏掉边界情况。
必须检查:
- Windows 版本是否链接了
kernel32.lib(MSVC 默认链接,但 MinGW 需显式加-lkernel32) - Linux 版本是否确保
STDOUT_FILENO可用(需,且程序运行在真正 tty 上) - 函数失败时不要 fallback 到硬编码值(如 80×24),这会让调试更难——应明确返回 false 并由上层决定默认策略
- 某些 IDE 内置终端(如 VS Code 的 integrated terminal)或 Windows Terminal 在调整窗口后不会自动触发重绘,但
GetConsoleScreenBufferInfo仍能读到新尺寸
为什么 std::cout 重定向后尺寸会失效?
因为 GetConsoleScreenBufferInfo 和 ioctl(TIOCGWINSZ) 都依赖底层文件描述符/句柄关联的终端设备。一旦 stdout 被重定向到文件或管道,这些调用就不再有意义——设备不再是 tty,系统无法提供“窗口尺寸”概念。
此时应:
- 提前缓存初始化时的尺寸(适用于短生命周期 CLI 工具)
- 让使用者通过参数传入(如
--cols=120),比猜测更可靠 - 检测是否为 tty:
_isatty(_fileno(stdout))(Windows)或isatty(STDOUT_FILENO)(POSIX),仅在此条件下调用尺寸查询
终端尺寸不是静态属性,它可能在程序运行中被用户改变,而 C++ 标准库不提供 resize 事件通知——需要轮询或依赖信号(如 SIGWINCH)自行处理,这点常被忽略。











