H5W3
当前位置:H5W3 > 其他技术问题 > 正文

`fflush(stdin)` 失败

//  sigdemo1.c - show how a signal handler works.
//  - run this and press Ctrl-C a few times
//  在第一次等待答复时,按下 Ctrl-C 只会出现 ^C 字符。
//  之后再按

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

extern void f(int);

int main(void) {
  signal(SIGINT, f);
  for (int i = 0; i < 5; ++i) {
    printf("blah blah blah\n");
    sleep(1);
  }
  return EXIT_SUCCESS;
}

extern void f(int signum) {
  printf("\tInterrupted! OK to quit (y/n)?");
  int c = getchar();
  if (c == EOF || c == 'y') {
    exit(EXIT_SUCCESS);
  }
  fflush(stdin);
}

在第一次发送 SIGINT 之后,输入 n 并回车,第二次中断时却在输出 Interrupted! OK to quit (y/n)? 之后就不接受输入,直接继续输出 blah blah blah, 第三次中断时才会接收输入。

怀疑 fflush(stdin) 没生效,求解。

回答:

之前的回答错了呜呜呜 QAQ

是这样子的,fflush(stdin) 在C标准里是行为未定义的,但是 glibc 说自己实现了这么个功能so。但是 glibc 2.20 骗人啦!它看看是不是存在未读取的数据,如果是,那么 lseek 回去!但很显然,连接到终端的 stdin 是不支持 lseek 的,所以就失败啦。glibc 只好忽略掉了。然后置位 _offset 字段为 _IO_pos_BAD加粗文字

cint
_IO_new_file_sync (fp)
     _IO_FILE *fp;
{
  _IO_ssize_t delta;
  int retval = 0;

  /*    char* ptr = cur_ptr(); */
  if (fp->_IO_write_ptr > fp->_IO_write_base)
    if (_IO_do_flush(fp)) return EOF;
  delta = fp->_IO_read_ptr - fp->_IO_read_end;
  if (delta != 0)
    {
#ifdef TODO
      if (_IO_in_backup (fp))
    delta -= eGptr () - Gbase ();
#endif
      _IO_off64_t new_pos = _IO_SYSSEEK (fp, delta, 1);
      if (new_pos != (_IO_off64_t) EOF)
    fp->_IO_read_end = fp->_IO_read_ptr;
#ifdef ESPIPE
      else if (errno == ESPIPE)
    ; /* Ignore error from unseekable devices. */
#endif
      else
    retval = EOF;
    }
  if (retval != EOF)
    fp->_offset = _IO_pos_BAD;
  /* FIXME: Cleanup - can this be shared? */
  /*    setg(base(), ptr, ptr); */
  return retval;
}

不知道这个是干什么的,反正 getchar 不理它:

cint
getchar (void)
{
  int result;
  _IO_acquire_lock (_IO_stdin);
  result = _IO_getc_unlocked (_IO_stdin);
  _IO_release_lock (_IO_stdin);
  return result;
}
c#define _IO_getc_unlocked(_fp) \
       (_IO_BE ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end, 0) \
    ? __uflow (_fp) : *(unsigned char *) (_fp)->_IO_read_ptr++)

PS: 在信号处理器里使用不可重入函数,是可能出问题的。

PPS: 不知道为什么,我这里在按第二次 Ctrl-C 时程序就被杀掉了。因为C库调用 rt_sigaction 时设置了 SA_RESETHAND 标志。

本文地址:H5W3 » `fflush(stdin)` 失败

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址