【问题标题】:How to safely drain stdin?如何安全地排出标准输入?
【发布时间】:2020-01-29 10:37:14
【问题描述】:

我读了几个相同的问题,但答案并不让我满意。

他们认为最好的答案是:

while((ch = getchar()) != '\n') && ch != EOF);

如果我想在我要求答案之前耗尽标准输入,就会出现问题,例如:

#define DRAIN() while((ch = getchar()) != '\n') && ch != EOF)
int fun() {
    ...
    DRAIN();       //aaa, wipe other's ass before me
    ch = getchar();//bbb, ask my answer
    DRAIN();       //ccc, wipe myown ass
    ...
}

'aaa' 的目的是排空 stdin 中之前代码留下的字符,可能在其他未知代码进入 fun() 之前。

但是,如果在 'aaa' 处,stdin 中没有字符,'aaa' 将在那里阻塞。

那么最好的选择是什么?

==================

我在下面试过了,没有效果。

#define DRAIN() do {                                        \
    char ch___ = 0;                                                \
    fd_set fds___;                                                 \
    struct timeval tv___;                                          \
    int ret___ = 0;                                                \
    FD_ZERO(&fds___);                                              \
    FD_SET(STDIN_FILENO, &fds___);                                 \
    tv___.tv_sec = 0;                                              \
    tv___.tv_usec = 5000;                                          \
    ret___ = select(STDIN_FILENO + 1, &fds___, NULL, NULL, &tv___);\
    printf("ret:%d\n", ret___);                                    \
    if (ret___ > 0) {                                              \
        while(getchar());                                          \
    }                                                              \
}while(0)

int main()
{
    printf("#");
    fflush(stdout);

    getchar();

    DRAIN();

    printf(">");
    fflush(stdout);
    printf(":%c\n", getchar());

    DRAIN();

    return 0;
}

$ ./a.out
#123
ret:0
>:2
ret:0

====第二次编辑====

看来这可行,我在 Linux 环境中:

#define DRAIN() do {                             \
    int flg___ = 0;                              \
    int flg___bak = 0;                           \
    char ch___ = 0;                              \
    flg___    = fcntl(STDIN_FILENO, F_GETFL, 0); \
    flg___bak = flg___;                          \
    flg___    |= O_NONBLOCK;                     \
    fcntl(STDIN_FILENO, F_SETFL, flg___);        \
    while((ch___ = getchar()) != '\n' && ch___ != EOF);  \
    fcntl(STDIN_FILENO, F_SETFL, flg___bak);     \
}while(0)

【问题讨论】:

  • 使用 ioctl。看this
  • 您是在控制台上制作游戏吗?控制台不适用于实时输入。这不是它的目的。有太多的问题需要解决,最好还是做个GUI应用,有windows之类的。
  • 您无法使用FILE* 执行此操作。您必须从文件描述符中read。所以没有getchar
  • @Dialectus 有很多主机游戏。这个概念没有错。
  • 无论如何,整件事都非常可疑。没有“先前代码留下的标准输入中的字符”。 stdin 中有用户预先输入的字符。如果您只是丢弃它们,用户将不会高兴。

标签: c stdin flush


【解决方案1】:

在过去的 DOS 中,我使用以下顺序:

while ( kbhit() )
{
    ch = getch();
}

kbhit() 是在 conio.h 中定义的,据我所知,它不可移植。但是,您可能很幸运能够访问它。

【讨论】:

    猜你喜欢
    • 2018-02-02
    • 2012-02-23
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 2011-09-13
    • 2017-08-11
    • 2010-12-25
    • 1970-01-01
    相关资源
    最近更新 更多