GetConsoleScreenBufferInfo 是 Windows 下获取控制台窗口字符尺寸最可靠的方法,需用 srWindow 计算宽高,而非 dwSize;Linux/macOS 应用 ioctl(TIOCGWINSZ) 获取 winsize,重定向时须 fallback 默认值;跨平台需先 isatty 检测终端有效性。

Windows 下用 GetConsoleScreenBufferInfo 读窗口尺寸最可靠
在 Windows 控制台程序里,GetConsoleScreenBufferInfo 是唯一能稳定拿到当前窗口宽高(字符单位)的系统调用。它返回的是缓冲区信息,但其中 srWindow 字段实际反映的是可视窗口大小——只要没手动缩放或全屏,这个值就是你看到的终端尺寸。
常见错误是直接读 dwSize,那是整个缓冲区大小,可能远大于窗口;或者忽略 COORD 的 X/Y 顺序(X 是列数/宽度,Y 是行数/高度)。
- 必须先用
GetStdHandle(STD_OUTPUT_HANDLE)拿句柄,不能传NULL或硬编码 - 调用后检查返回值,失败时
GetLastError()通常为ERROR_INVALID_HANDLE(比如重定向了 stdout) - 结果中的
srWindow.Right - srWindow.Left + 1才是真实列数,srWindow.Bottom - srWindow.Top + 1是行数
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
int width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}Linux/macOS 用 ioctl(TIOCGWINSZ) 获取终端行列数
POSIX 系统没有“控制台窗口”概念,而是靠终端驱动暴露的 winsize 结构。核心是向 STDIN_FILENO 或 STDOUT_FILENO 发送 TIOCGWINSZ 请求,不是读环境变量或调用 curses。
容易踩的坑:重定向时(比如 ./a.out > out.txt)ioctl 会失败,此时应 fallback 到默认值(如 80×24),而不是 crash 或返回 0。
立即学习“C++免费学习笔记(深入)”;
- 头文件必须包含
<sys/ioctl.h>和<>termios.h> - 结构体
winsize的ws_col是列数(宽度),ws_row是行数(高度) - 某些容器环境(如 Docker 默认 tty=false)下该调用始终失败,需提前判断
struct winsize w;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
int width = w.ws_col;
int height = w.ws_row;
}跨平台封装要注意 stdin 重定向和伪终端场景
写一个跨平台函数时,不能只拼 Windows/Linux 分支。真正麻烦的是:当程序被管道、重定向或 IDE 内置终端运行时,原生 API 全部失效——GetConsoleScreenBufferInfo 返回 false,ioctl 返回 -1,且 errno 不一定有意义。
这时候硬查尺寸没意义,反而应该信任用户输入或设安全默认值。强行 fallback 到 getenv("COLUMNS") 或 stty size 调用,会引入额外依赖和竞态。
- 优先检测是否为真实终端:
_isatty(_fileno(stdout))(Windows)或isatty(STDOUT_FILENO)(POSIX) - 非终端环境直接返回预设值(如 80, 24),不要尝试解析环境变量
- 避免在子进程或 DLL 中缓存尺寸结果——窗口可能随时被拖拽改变
别用 system("mode con") 或 GetSystemMetrics
这两个方法看似简单,实际完全不可靠。system("mode con") 会闪黑窗、阻塞主线程、输出解析困难,且在无 cmd.exe 的环境(如 WSL2 的默认配置)直接失败;GetSystemMetrics(SM_CXSCREEN) 返回的是整个屏幕像素宽,不是控制台字符宽度,更不考虑字体缩放、DPI 设置。
它们既无法提供字符单位尺寸,也无法反映当前终端实际可视区域,属于典型的“看起来能跑,其实错得离谱”方案。
-
mode con输出格式随系统语言变化(中文 Win 下是“列数:”,英文是“Columns:”),没法稳定 parse -
GetSystemMetrics对多显示器、缩放比例为 125%/150% 的情况完全无感知 - 任何需要 fork / popen / CreateProcess 来间接获取尺寸的方案,都比直接调用原生 API 更慢、更脆
实际用的时候,窗口尺寸不是静态值——用户拖动边缘、切换全屏、甚至远程 SSH 连接断开重连,都会触发变化。如果业务逻辑真依赖实时尺寸(比如动态渲染表格),得监听 WINDOW_BUFFER_SIZE_EVENT(Windows)或 SIGWINCH(POSIX),而不是只在启动时查一次。










