Windows 下用 GetConsoleScreenBufferInfo 可靠获取控制台行列数;Linux/macOS 下应读取 ioctl 的 TIOCGWINSZ,不能依赖环境变量或 stty 命令。
Windows 下用 GetConsoleScreenBufferInfo 可靠获取控制台行列数;Linux/macOS 下应读取 ioctl 的 TIOCGWINSZ,不能依赖环境变量或 stty 命令。
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; }
ioctl 调用 TIOCGWINSZ
POSIX 系统没有统一的“控制台大小 API”,ioctl 是标准且最可靠的方式。它直接向终端设备查询当前窗口尺寸,不受 shell 类型或重定向影响(只要 stdout 是 tty)。
常见误区:
$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 容易漏掉边界情况。
必须检查:
kernel32.lib(MSVC 默认链接,但 MinGW 需显式加 -lkernel32)STDOUT_FILENO 可用(需 ,且程序运行在真正 tty 上)GetConsoleScreenBufferInfo 仍能读到新尺寸std::cout 重定向后尺寸会失效?因为 GetConsoleScreenBufferInfo 和 ioctl(TIOCGWINSZ) 都依赖底层文件描述符/句柄关联的终端设备。一旦 stdout 被重定向到文件或管道,这些调用就不再有意义——设备不再是 tty,系统无法提供“窗口尺寸”概念。
此时应:
--cols=120),比猜测更可靠_isatty(_fileno(stdout))(Windows)或 isatty(STDOUT_FILENO)(POSIX),仅在此条件下调用尺寸查询终端尺寸不是静态属性,它可能在程序运行中被用户改变,而 C++ 标准库不提供 resize 事件通知——需要轮询或依赖信号(如 SIGWINCH)自行处理,这点常被忽略。