终端原始模式下的奇怪行为

Strange behavior in terminal raw mode

我正在学习制作文本编辑器的教程。 到目前为止,它一直在修补原始模式。下面的代码应该关闭规范模式,并输出每个按键。

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

struct termios orig_termios;
void disableRawMode() { … }
void enableRawMode() { … }

int main() {
  enableRawMode();
  char c;
  while (read(STDIN_FILENO, &c, 1) == 1 && c != 'q') {
    if (iscntrl(c)) {
      printf("%d\n", c);
    } else {
      printf("%d ('%c')\n", c, c);
    }
  }
  return 0;
}

我原来忘记在printf()语句后面加上"\n",结果在程序结束后我只得到了输出的字符,即在这个例子中按下 q 之后。 但是,在添加 "\n" 之后,终端会按按下的方式输出每个字母。

有谁能解释一下为什么会这样吗?

通常,当 C 程序以连接到终端的标准输出流启动时,该流是行缓冲的。这意味着使用 printf 或标准库方法打印的字符将保留在缓冲区中,直到打印 \n (结束该行,因此“行缓冲”),缓冲区已满,当流被手动刷新时(与 fflush 一样),或者当在无缓冲或行缓冲的流上请求输入但需要来自“主机环境”(尤其是人类)的字符时。

终端设置无关紧要,因为字符保存在标准 C 库实现的内部缓冲区中,并且直到上述事件之一才会发送到终端。

您可以在对 stdout 执行任何其他操作之前调用 setvbuf(stdout, NULL, _IONBF, 0) 将流设置为无缓冲。

原始模式是终端的关注点,但stdout的缓冲区管理发生在到达终端之前。

默认情况下,当文件描述符 1 (STDOUT_FILENO) 是 link 到终端时,stdout 使用 -缓冲策略。 这意味着 stdout 的输出缓冲区在写入 \n 时(或已满)刷新到文件描述符 1。 只有在这一刻,角色才能到达终端,终端可以根据其配置以不同的方式做出反应。

在您的示例中,字符仅保留在内存中,直到进程终止(stdout 此时已刷新)。