关于getchar()循环如何在内部工作的困惑

时间:2014-03-17 00:15:57

标签: c io internals getchar

我已经在下面使用getchar()添加了一个示例程序,以供参考(并非任何人都可能需要它),如果您愿意,可以随意解决它的问题。但我的问题是:

该计划调用getchar() 时究竟发生了什么?

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

  1. 调用getchar时,它会检查STDIN缓冲区以查看是否有任何输入。
  2. 如果没有输入,getchar就会睡觉。
  3. 唤醒后,getchar检查是否有任何输入,如果没有,则让它自己再次入睡。
  4. 重复步骤2和3直到有输入。
  5. 一旦有输入(按照约定包括最后的EOF'),getchar返回此输入的第一个字符并执行某事以指示下一个调用getchar应该从同一个缓冲区返回第二个字母?我不确定那是什么。
  6. 当除了EOF之外没有其他字符时,getchar是否会刷新缓冲区?
  7. 我使用的术语可能不太正确。

    #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;
    }
    

1 个答案:

答案 0 :(得分:5)

步骤2-4稍微关闭。

如果标准I / O缓冲区中没有输入,getchar()会调用一个函数来重新加载缓冲区。在类Unix系统上,通常最终调用read()系统调用,read()系统调用将进程置于睡眠状态,直到有待处理的输入,或者内核知道会有没有要处理的输入(EOF)。当读取返回时,代码调整数据结构,以便getchar()知道有多少数据可用。你的描述意味着民意调查;标准I / O系统不会轮询输入。

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

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

  

所以基本上,而不是轮询,是命中返回导致某个I / O中断,然后当操作系统收到此信息时,它会唤醒任何为I / O休眠的进程?

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

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

我说“名义上”因为有一个外部机会实际上终端应用程序通过pty(伪tty)调解I / O,但我认为它发生在内核级别并且终端应用程序公平地参与在这个过程的后期。键入的键盘和键入的显示器之间存在巨大的脱节。

另见Canonical vs non-canonical terminal input