如何在C中实现在终端中擦除输出?

14 浏览
0 Comments

如何在C中实现在终端中擦除输出?

有些在终端运行的应用程序可以擦除它们的输出。例如,当它告诉你等待时,它会显示一系列点,点的长度会交替变化。在C语言中,终端输出的擦除是如何实现的?是通过反向换行符完成的吗?一个程序只能擦除当前行中的先前字符,而不能擦除stdout中上一行的字符吗?谢谢。

0
0 Comments

在C中实现终端中的擦除输出有多种方法,具体取决于终端的类型。

在Windows操作系统中,COMSPEC shell(通常称为DOS提示符或command.com)提供了一个C API来控制光标,但对于Windows编程我了解有限,无法提供详细信息。

大多数其他终端(尤其是Unix系统上的终端)模拟的是类似于VT100串行终端的协议(VT100终端是一个物理设备,用于连接调制解调器或串行端口以与服务器通信)。

在VT100终端上,回车和换行是单独的命令,每个命令占用一个字节。回车命令将光标设置到行的开头,而换行命令将光标向下移动一行(但不会自动将光标移到行的开头)。大多数Unix系统上的shell会在换行符后自动插入回车符,但几乎没有在回车符后插入换行符。

基于这些知识,最简单的实现方法是输出回车符并重新打印整行:printf("\rprogress: %d percent ", x);。注意行末的额外空格。打印"\r"并不会擦除行,所以在旧行上重新打印可能会导致旧字符串的一部分仍然显示在屏幕上。额外的空格用于尝试擦除旧行的剩余部分。

如果你在谷歌上搜索"VT100 escape secquence",你会找到一些命令,可以用来擦除当前行、改变文本颜色、定位到屏幕上的特定行/列等。VT100序列最常用于输出彩色文本,但也可以用于其他用途。

下一个更简单的实现方法是清除并重新打印整行:printf("\033[2K\rprogress: %d percent", x);。其中\033[2K是删除当前行的转义序列(ESC[2K)。

如果你想更有创意,可以使用保存/恢复光标命令和擦除至行尾命令,只擦除要更新的部分(而不是整行)。也可以使用定位命令将光标放置在屏幕上的特定位置以更新该位置的文本等。

需要注意的是,更高级的功能(如VT102序列或一些完整的ANSI转义序列)通常在不同的终端之间不可移植(这里的终端指的是rxvt、xterm、Linux终端、Windows的超级终端等)。

如果要实现可移植性(和/或合理的API),应使用curses或ncurses库。

需要注意的是,所有这些方法都不仅限于C语言。你可以在shell脚本中或任何脚本语言(甚至是makefile)中使用。这就是了解VT100命令的真正价值所在——当无法使用curses或ncurses时。

至于如何实现,以上就是方法。只需将特殊格式的字符串打印到屏幕上(除了COMSPEC shell)。有点像HTML,但是老派的。

需要注意的是,这些方法都不是特定于C语言的。如果需要,你可以在shell脚本或任何脚本语言(甚至是makefile)中使用这些方法。这就是了解VT100命令的真正价值所在——当无法使用curses或ncurses时。

0