【问题标题】:How to deactivate input statement after some time?一段时间后如何停用输入语句?
【发布时间】:2013-08-19 19:45:46
【问题描述】:

我们知道输入函数或运算符(cin、scanf、gets….etc)等待从用户那里获取输入,这个时间没有限制。

现在,我会问一个问题,用户给出答案,到目前为止没有问题,但我的问题是“用户有时间(可能是 30 或 40 秒)给出输入,如果他失败则输入语句将自动停用并执行下一条语句。”

我想你明白我的问题了。那么请在这种情况下帮助我。如果有人给我一些真正有效的示例代码会更好。

我在 Windows 7 中使用 codebolck 12.11。

【问题讨论】:

  • 标准 C++ 对您没有任何帮助。您需要使用一些或多或少邪恶的特定于操作系统的技巧。
  • 感谢您的回复。请给我一些示例或功能。
  • 不,因为我不知道你的操作系统是什么。
  • 这个链接会很有帮助。在这里,您会发现另外两个链接,这些链接包含不同语言的 sn-ps 以及某种解释。 bytes.com/topic/c-sharp/answers/…
  • 我的操作系统是 windows 7,编译器是代码块 12.11

标签: c++ c input cin


【解决方案1】:

*IX'ish 系统的方法(包括 Windows 上的 Cygwin):

您可以使用alarm() 安排SIGALRM,然后使用read(fileno(stdin), ...)

当信号到达时,read() 将返回 -1,并将 errno 设置为 EINTR

例子:

#define _POSIX_SOURCE 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

void handler_SIGALRM(int signo)
{
  signo = 0; /* Get rid of warning "unused parameter ‘signo’" (in a portable way). */

  /* Do nothing. */
}

int main()
{
  /* Override SIGALRM's default handler, as the default handler might end the program. */
  {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));

    sa.sa_handler = handler_SIGALRM;

    if (-1 == sigaction(SIGALRM, &sa, NULL ))
    {
      perror("sigaction() failed");
      exit(EXIT_FAILURE);
    }
  }

  alarm(2); /* Set alarm to occur in two seconds. */

  {
    char buffer[16] = { 0 };

    int result = read(fileno(stdin), buffer, sizeof(buffer) - 1);
    if (-1 == result)
    {
      if (EINTR != errno)
      {
        perror("read() failed");
        exit(EXIT_FAILURE);
      }

      printf("Game over!\n");
    }
    else
    {
      alarm(0); /* Switch of alarm. */

      printf("You entered '%s'\n", buffer);
    }
  }

  return EXIT_SUCCESS;
}

注意:在上面的示例中,对read() 的阻塞调用将在任何信号到达时中断。避免这种情况的代码留给读者执行... :-)

【讨论】:

    【解决方案2】:

    另一种方法:
    您可以使用 POSIX select() 函数(以及一些宏 FD_ZEROFD_SETFD_ISSET)来检查哪些文件描述符(描述符编号 0 即标准输入,在这种情况下)已准备好在给定中读取时间间隔。当它们准备好后,使用适当的函数读取数据(在这种情况下为scanf())。
    这段代码可能会帮助你理解我想说的:

    #include <sys/select.h>
    #include <sys/time.h>
    #include <stdio.h>
    
    #define STDIN    0    // Standard Input File Descriptor
    int main()
    {
        fd_set input;       // declare a "file descriptor set" to hold all file descriptors you want to check
        int fds, ret_val, num;  // fds: Number of file descriptors;
    
        struct timeval tv;      // structure to store Timeout value in the format used by select() function
        unsigned int timeout = 5;   // Your timeout period in seconds
    
        tv.tv_sec = timeout;    
        tv.tv_usec = 0;
    
        fds = STDIN + 1;            // Set number of file decriptors to "1 more than the greatest file descriptor"
                    // Here, we are using only stdin which is equal to 0
    
        FD_ZERO(&input);        // Initialize the set with 0
        FD_SET(STDIN, &input);      // Add STDIN to set
    
        printf("Enter a number within %d secs\n", timeout);
        ret_val = select(fds, &input, NULL, NULL, &tv); 
                    // We need to call select only for monitoring the "input file descriptor set"
                    // Pass rest of them as NULL
    
        if (ret_val == -1)          // Some error occured
            perror("select()");
        else if (ret_val > 0)       // At least one of the file descriptor is ready to be read
        {
    //      printf("Data is available now.\n");
            if(FD_ISSET(0, &input))     // Check if stdin is set, here its not necessary as we are using STDIN only
                    // So ret_val>0 means STDIN is raedy to read 
            {
                scanf("%d", &num);
            }
        }
        else
            printf("No data within five seconds.\n");   // select returns zero on timeout
    
        return 0;
    }
    

    更多帮助: select(2)

    您也可以尝试使用(同样是 POSIX 标准函数)中提供的 poll() 函数作为 select() 的替代方法。见poll() & poll(2)

    【讨论】:

    • 我只是想提出同样的建议。 (有时您可能希望在 ret_val == -1 子句中处理 EINTR。)要将其移植到 Windows,请查看以下问题:stackoverflow.com/q/933745/1025391
    • 感谢@moooeeeep 的链接!我也想知道类似的代码如何在基于 Windows 的系统下工作。我忘了在我的回答中提到这种不可移植性。
    • #include #include 我的编译器找不到这样的头文件。我使用 codebolck 12.11
    • 您使用哪种操作系统?正如@moooeeeeep 所指出的,这仅适用于“具有POSIX 库”的基于UNIX 的系统(您可以使用man selectman pselect 等进行检查,如果出现帮助,则说明您拥有这些库),因为Windows,你可以点击他发布的链接。
    • @Xplosive:还要检查库的正确路径,如果它们不在默认路径上,请使用-L 选项指定gcc
    【解决方案3】:
    #include <cstddef>
    #include <ctime>
    #include <iostream>
    #include <conio.h>
    
    bool get_input ( char *buffer, std::size_t size, int timeout )
    {
         std::time_t start = std::time ( 0 );
         std::size_t n = 0;
    
       for ( ; ; ) {
        if ( n == 0 && std::difftime ( std::time ( 0 ), start ) >= timeout )
         return false;
    
        if ( kbhit() ) {
      if ( n == size - 1 )
        break;
    
      char ch = (int)getche();
    
      if ( ch == '\r' ) {
        buffer[n++] = '\n';
        break;
      }
      else
        buffer[n++] = ch;
      }
    }
    
     buffer[n] = '\0';
    
    return true;
    }
    
     int main()
    {
    char buffer[512] = {0};
    
    if ( !get_input ( buffer, 512, 5 ) ) {
    std::cout<<"Input timed out\n";
    buffer[0] = '\n';
    }
    
    std::cout<<"input: \""<< buffer <<"\"\n";
    }
    

    【讨论】:

    • 我在代码块 13.2 中运行此代码,它在一段时间后工作正常,程序使用此代码自动结束是否有可​​能将其用于 cin ????
    • 此代码使用非标准 C、非 POSIX 功能,并且具有高度不可移植性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    相关资源
    最近更新 更多