对 getchar() 循环的内部工作方式感到困惑

标签 c io internals getchar

我在下面包含了一个使用 getchar() 的示例程序,以供引用(并不是说任何人都可能需要它),如果您愿意,请随时解决问题。但我的问题是:

当程序调用 getchar() 时到底发生了什么?

这是我的理解(请澄清或纠正我):

  1. 调用 getchar 时,它会检查 STDIN 缓冲区以查看是否有任何输入。
  2. 如果没有任何输入,getchar 就休眠。
  3. 唤醒后,getchar 检查是否有任何输入,如果没有,则使其再次进入休眠状态。
  4. 重复第 2 步和第 3 步,直到有输入为止。
  5. 一旦有输入(按照惯例,末尾包含一个“EOF”),getchar 返回该输入的第一个字符,并做一些事情以指示下一次调用 getchar 应该返回来自同一个缓冲区的第二个字母?我不太确定那是什么。
  6. 当除 EOF 外没有剩余字符时,getchar 是否刷新缓冲区?

我使用的术语可能不太正确。

#include <stdio.h>

int getLine(char buffer[], int maxChars);

#define MAX_LINE_LENGTH 80

int main(void){

    char line[MAX_LINE_LENGTH];
    int errorCode;

    errorCode = getLine(line, sizeof(line));
    if(errorCode == 1)
        printf("Input exceeded maximum line length of %d characters.\n", MAX_LINE_LENGTH);
    printf("%s\n", line);

    return 0;

}

int getLine(char buffer[], int maxChars){
    int c, i = 0;
    while((c = getchar()) != EOF && c != '\n' && i < maxChars - 1)
        buffer[i++] = c;
    buffer[i++] = '\0';
    if(i == maxChars)
        return 1;
    else
        return 0;
}

最佳答案

第 2-4 步略有偏差。

如果标准 I/O 缓冲区中没有输入,getchar() 调用函数重新加载缓冲区。在类 Unix 系统上,这通常以调用 read() 系统调用结束,而 read() 系统调用使进程进入休眠状态,直到有输入被处理,或者内核知道没有要处理的输入(EOF)。当读取返回时,代码调整数据结构,以便 getchar() 知道有多少数据可用。您的描述暗示轮询;标准 I/O 系统不轮询输入。

第 5 步使用调整后的指针返回正确的值。

确实没有 EOF 字符;它是一种状态,而不是一种性格。即使您键入 Control-DControl-Z 来指示“EOF”,该字符也不会插入到输入流中。事实上,这些字符会导致系统刷新任何仍在等待“行编辑”操作(如退格键)更改它们的键入字符,以便它们可用于 read() 系统调用.如果没有这样的字符,则 read() 返回 0 作为可用字符数,这意味着 EOF。然后 getchar() 返回值 EOF(通常是 -1 但保证为负数,而有效字符保证为非负数(零或正))。

So basically, rather than polling, is it that hitting Return causes a certain I/O interrupt, and then when the OS receives this, it wakes up any processes that are sleeping for I/O?

是的,点击Return 会触发中断,操作系统内核会处理它们并唤醒正在等待数据的进程。当中断发生时,终端驱动程序被内核唤醒,并决定如何处理刚刚接收到的字符。它们可能被隐藏以供进一步处理(规范模式)或立即可用(原始模式)等。当然,假设输入是终端;如果输入来自磁盘文件,那么它在很多方面都更简单——或者如果它是一个管道,或者……

名义上,被中断唤醒的不是终端应用程序;内核首先被唤醒,然后在终端应用程序中运行的 shell 被唤醒,因为有数据可供它读取,只有当有输出时,终端应用程序才会被唤醒。

我说“名义上”是因为实际上终端应用程序确实通过 pty(伪 tty)调解 I/O 的可能性很小,但我认为它发生在内核级别并且终端应用程序公平地参与其中在这个过程的后期。在您键入的键盘和显示您键入的内容的显示器之间确实存在巨大的脱节。

另见 Canonical vs non-canonical terminal input .

关于对 getchar() 循环的内部工作方式感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22444932/

相关文章:

c - 是什么原因导致 "left but not entered"GCC 编译器错误?

c - 有没有办法检查我的代理是否在线?

io - Erlang消费者队列

android - 什么是了解 Android 操作系统内存管理的好资源?

c# - linq2sql 如何跟踪数据库对象?

c - 卡在有关数组和移动数字的代码上

java - python解释器到底是用什么实现的?

c++ - boost::bind 内部拷贝/拷贝?

go - ioutil.ReadAll 惨遭失败

java - 是否可以中断 Scanner.hasNext()