【问题标题】:How to make a C program stop a loop from any user input?如何使 C 程序停止任何用户输入的循环?
【发布时间】:2012-11-17 00:56:54
【问题描述】:

我想编写一个运行无限循环的小型 C 程序,直到用户按下键盘上的一个键(即:标准输入缓冲区中有一个字符)。我在打破用户输入循环时遇到了麻烦。我尝试过使用fgetc,但这并不符合预期。下面的代码等待用户输入,而不是运行直到用户输入。

示例 C 代码:

while((c=fgetc(stdin) == EOF) {
  /* Does stuff for infinite loop here */
  printf("Example work in the loop\n");
}
printf("Out of the loop!\n");

如何编写一个在用户干预之前一直执行的循环?按下任何键或特定键都可能是干预触发器。

注意 1:我正在为 Unix 控制台写这个,以防平台特定的解决方案

注意2:不要建议Ctrl + C/X/Z作为用户干预触发器

【问题讨论】:

  • 如果你的程序有一个用于标准输入的 tty,用户键入一个键将不会为程序提供任何输入。 tty 不会向您的程序发送任何内容,直到用户点击“输入”或通过 ^C 或 ^] 或 ^Z 发送信号。澄清你的问题。您是要响应输入,还是要响应键盘事件。两者是不同的。
  • @WilliamPursell 哪个更容易实现,输入还是键盘事件?
  • 您可以使用poll(2) 系统调用。

标签: c infinite-loop user-interaction


【解决方案1】:

这似乎对我有用:

#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

static void set_non_blocking(int fd)
{
    int flags  = fcntl(fd, F_GETFL, 0 );
    flags |= O_NONBLOCK;
    flags = fcntl(fd, F_SETFL, flags);
}


int main(int argc, char ** argv)
{
    int fd = fileno(stdin);
    char buf[10];

    set_non_blocking(fd);

    while (read(fd, buf, sizeof buf) < 0) {
        perror("read");
        sleep(1);
    }
    return 0;
}

或者你可以使用select:

int main(int argc, char ** argv)
{
    int fd = fileno(stdin);
    struct timeval tv = {0,0};
    fd_set fdset;
    int s;

    do {
        sleep(1);
        FD_ZERO(&fdset);
        FD_SET(fd, &fdset);

    } while ((s = select(fd+1, &fdset, NULL, NULL, &tv)) == 0);

    if (s < 0) {
        perror("select");
    }
    return 0;
}

投票也有效 :-)

int main(int argc, char ** argv)
{
    struct pollfd pfd;
    int s;

    pfd.fd = fileno(stdin);
    pfd.events = POLLRDNORM;

    while ((s = poll(&pfd, 1, 0)) == 0) {
        perror("polling");
        sleep(1);
    }
    if (s < 0) {
        perror("poll");
    }
    return 0;
}

最后一种方法是将终端设置为“原始”模式。请注意,这会扰乱终端的输出(至少在我的 OS-X 上),因为在 \n 之后 \r 变得必要。另请注意,它需要在最后撤消(终止 tcsetattr 调用)。这是唯一不需要 \n 的(即任何按键都可以)

#include <poll.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>


static void set_non_blocking(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0) | O_NONBLOCK;

    if (fcntl(fd, F_SETFL, flags) < 0) {
        perror("fcntl");
        exit(EXIT_FAILURE);
    }
}


int main(int argc, char ** argv)
{
    struct termios params;
    struct termios params_orig;
    char buf[10];
    int fd = fileno(stdin);

    if (tcgetattr(fd, &params) < 0) {
        perror("tcgetattr");
        exit(EXIT_FAILURE);
    }
    params_orig = params;

    cfmakeraw(&params);

    if (tcsetattr(fd, TCSANOW, &params) < 0) {
        perror("tcsetattr");
        exit(EXIT_FAILURE);
    }
    set_non_blocking(fd);

    while (read(fd, buf, sizeof buf) < 0) {
        perror("\rread");
        sleep(1);
    }

    (void) tcsetattr(fd, TCSANOW, &params_orig);
    return 0;
}

【讨论】:

  • 这似乎也对我有用! (仅当按下回车键时)
  • 我喜欢select(),因为它不是 *nix 特定的
猜你喜欢
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 2016-12-23
  • 2022-09-29
  • 1970-01-01
  • 1970-01-01
  • 2016-03-14
  • 1970-01-01
相关资源
最近更新 更多