【问题标题】:Using getchar() after read()在 read() 之后使用 getchar()
【发布时间】:2009-10-03 16:52:55
【问题描述】:

c 用于键盘捕获。以下代码查找何时按下箭头键/ esc。同时,我想阅读用户输入的整个单词,这些单词也应该显示在 stdout 上。

char pp = 0;
char p = 0;
while( (i = read(0, &c, 1)) == 1) {
if (pp == 033 && p == 0133 && (c &= 255) == 0102) /* DOWN */ break;
if (c == 0177) /* ASCII DELETE */ break;
printf( "%o, %o, %o\t%s\n\r", pp, p, c, &c);
pp = p;
p = c; 
}
...
...
getchar(); //I want to capture here what was entered before
           //  **return key** was pressed.

但如果我删除 '\n',此代码将不起作用。 我希望 stdout 的行为与普通 shell 一样。

【问题讨论】:

    标签: c unix console stdout stdin


    【解决方案1】:

    printf(3) 通过 <stdio.h> 缓冲 I/O 设施,其中包括 fputs(3)fputc(3)。您正在观察正常的行缓冲行为。您可以按照setbuf(3) 的说明解决此缓冲问题,但是,由于您一开始并不想要它,而且您已经在使用直接内核调用 (read(2)) 进行读取,为什么不稍微改变一下您的逻辑直接用write(2)调用内核?

    char buffer[100];
    
    int n;
    
    n = snprintf(buffer, sizeof buffer, "format string...", args...);
    write(1, buffer, n)
    

    如果您愿意,您可以定义自己的 directPrintf 来简化此操作:

    #include <stdio.h>
    #include <stdarg.h>
    #include <unistd.h>
    
    int directPrintf(const char *format, ...)
    {
    va_list ap;
    char buffer[200];
    
        va_start(ap, format);
        int n = vsnprintf(buffer, sizeof buffer, format, ap);
        va_end(ap);
        return write(1, buffer, n);
    }
    

    【讨论】:

      【解决方案2】:

      getchar() 很可能是根据读取远远超过 1 个字节(通常是整个 PIPE_BUF 或 4096 个字节)的read() 来实现的。然后它维护一个指向该缓冲区的私有游标,根据需要提取字节。

      这样做是因为read() 具有与仅调用它相关的重要开销。

      printf()fwrite()(等等)也出于同样的原因缓冲(write() 有一个不小的开销)。对 fflush(stdout) 的调用将转换为对已缓冲但未发送到底层 IO 端口的任何内容的 write() 调用。

      最后,你有\n\r 倒退;几乎可以肯定应该是\r\n

      【讨论】:

        【解决方案3】:

        插入

        setbuf( stdout, NULL);
        

        在开头的某处删除\n。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多