ncurses 是什么?它和 curses 有什么关系

ncurses 是 curses 终端控制库的一个开源实现,用来在字符终端里控制光标位置、颜色、窗口和键盘输入。curses 是一套接口规范(最初来自 System V 的 terminfo/curses 体系),ncurses 是遵循这套接口、可自由使用的具体库。你在 Linux、BSD、macOS 上写文本界面程序时调用的 initscr()、mvaddstr()、refresh() 等函数,通常就来自 ncurses。Lynx 这类文本浏览器正是靠它把网页渲染成终端里可滚动的字符画面。

curses 与 ncurses:规范与实现

维度 curses ncurses
性质 终端控制接口的统称/规范 该接口的一个开源实现
来源 早期 Unix 终端库传统 由社区维护,现由 Thomas Dickey 等维护
可移植性 不同系统实现可能不同 在类 Unix 系统上广泛可用,行为较一致
关系 定义“能做什么” 提供“具体怎么做”的代码

所以“用 curses 编程”通常指使用这套 API,而实际链接的库往往是 ncurses。Lynx 的官网把 curses 和 ncurses 都列为关键词,也说明它依赖这一层终端能力。

ncurses 解决什么问题

终端本身只提供字符流和一组转义序列。不同终端(xterm、vt100、linux console 等)的转义序列并不完全一样。ncurses 通过 terminfo 数据库把这些差异封装起来,让程序用统一函数完成:

  • 在指定行列输出文字、移动光标
  • 创建和管理多个窗口(window)、面板(panel)
  • 处理颜色对(color pair)和属性(加粗、反显等)
  • 读取功能键、方向键等特殊按键
  • 在退出时恢复终端原有状态

Lynx 就是在这个基础上实现“文本网页浏览器”:把 HTML 转成终端可显示的字符布局,并支持在页面里上下滚动、跟随链接。

基本使用方式

使用 ncurses 需要包含头文件并链接库。典型编译命令:

cc program.c -lncurses

如果用到宽字符或面板、菜单等扩展,链接的库名会不同,例如:

cc program.c -lncursesw   # 宽字符支持
cc program.c -lpanel      # 面板扩展
cc program.c -lmenu       # 菜单扩展

一个最小程序的结构是:调用 initscr() 初始化,用 printw() 或 mvaddstr() 输出,refresh() 刷新屏幕,最后 endwin() 恢复终端。输入、动作、预期结果对应为:初始化后进入 curses 模式 → 输出内容并刷新 → 退出时终端回到正常状态。

常见卡点

  • TERM 未设置或设置错误:ncurses 依赖 TERM 环境变量查找 terminfo 条目。TERM 为空或不匹配时,程序可能报错或显示乱码。可用 echo $TERM 检查。
  • 忘记 endwin():异常退出会让终端停留在 curses 模式,出现无回显、光标异常等现象,通常用 reset 命令恢复。
  • 颜色未初始化:使用颜色前要调用 start_color() 并定义颜色对,否则颜色设置不生效。
  • 宽字符问题:处理中文等多字节字符时,普通 ncurses 可能显示异常,需要宽字符版本 ncursesw 并配合相应函数。
  • 刷新时机:ncurses 采用缓冲式更新,不调用 refresh() 或 wrefresh() 时屏幕不会立即变化。

和 Lynx 的关系

Lynx 是运行在终端里的文本浏览器,它的界面滚动、链接高亮、状态行等都由 curses/ncurses 这类库支撑。理解 ncurses 有助于明白:为什么 Lynx 能在没有图形环境的服务器上工作,以及为什么它的显示效果会受 TERM 和终端类型影响。

lynx.invisible-island.net
Thomas Dickey is the maintainer/developer of the Lynx text-browser. This page gives some background and pointers to Lynx resources.