我可以让ungetc解除阻止fgetc呼叫吗?

我可以让ungetc解除阻止fgetc呼叫吗?,c,stdin,blocking,C,Stdin,Blocking,我想在收到SIGUSR1后使用ungetc将一个“A”字符塞回stdin。想象一下,我这样做有一个很好的理由 调用foo()时,stdin中的阻塞读取不会被收到信号时的ungect调用中断。虽然我没想到会这样,但我想知道是否有办法做到这一点——有人有什么建议吗 void handler (int sig) { ungetc ('A', stdin); } void foo () { signal (SIGUSR1, handler); while ((key = fgetc (s

我想在收到SIGUSR1后使用ungetc将一个“A”字符塞回stdin。想象一下,我这样做有一个很好的理由

调用foo()时,stdin中的阻塞读取不会被收到信号时的ungect调用中断。虽然我没想到会这样,但我想知道是否有办法做到这一点——有人有什么建议吗

void handler (int sig) { ungetc ('A', stdin); } void foo () { signal (SIGUSR1, handler); while ((key = fgetc (stdin)) != EOF) { ... } } 无效处理程序(int sig) { ungetc('A',stdin); } void foo() { 信号(SIGUSR1,处理器); while((key=fgetc(stdin))!=EOF) { ... } }
现在还不完全清楚你的目标是什么,但这就是你想要的吗

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

int handle = 0;

void handler (int sig) {
  handle = 1;
}

void foo () {
  int key;

  signal (SIGUSR1, handler);

  while ((key = fgetc (stdin)) != EOF) {
    printf("%c\n",key);
    if (handle) {
      handle = 0;
      ungetc('A',stdin);
    }
  }
}

int main(void) {
  printf("PID: %d\n",getpid());
  foo();
}

文件不是异步安全的

当其他人也使用同一文件*时,不能在信号处理程序中对文件*进行操作。可以在信号处理程序中使用的所有函数如下所述:

。(可能是
在windows机器上不同,但仍然有任何文件*在那里也不安全。

这与@Jamie的答案基本相同,稍作修改以支持您在
t
之前处理
a
,但在注释框中键入代码太难了,因此我单独发布了此答案

int insert_an_A = 0;
void handler(int sig) { insert_an_A = 1; }

void process_char(char c) { ... }

int main(int argc, char **argv) {
    int c;
    /* skip signal setup */
    while ((c = fgetc(stdin)) != EOF) {
        if (insert_an_A) {
            process_char('A');
            insert_an_A = 0;
        }
        process_char(c);
    }
}
如果要处理在调用
fgetc
期间接收到的返回
EOF
的处理程序,还应在退出while循环后选中
insert\an\u A


还要注意,一般来说,信号处理程序的最佳实践是设置一个全局变量并从处理程序返回。在程序的其他地方,寻找该变量的变化并做出适当的反应。

而不是尝试获取
ungetc()
以解除阻塞
fgetc()
通过信号调用,也许您可以尝试不使用
fgetc()
块开始,并使用
select()
等待stdin上的活动


默认情况下,终端设备的行规程可以在规范模式下工作。在此模式下,终端驱动程序在看到换行符(按下Enter键)之前不会向用户空间显示缓冲区

要完成您想要的操作,您可以使用
操作
termios
结构,将终端设置为原始(非规范)模式。这将阻止调用
fgetc()
,以立即返回插入的字符
ungetc()

注意:为了简单起见,此代码省略了错误检查。

清除
ECHO
ICANON
标志分别会禁用键入字符时的回显,并导致直接从输入队列满足读取请求。将
c撸cc
数组中的
VTIME
VMIN
的值设置为零会导致读取请求(
fgetc()
)立即返回而不是阻塞;有效地轮询stdin。这会导致
键设置为
EOF
,因此需要另一种终止循环的方法。通过使用
select()
等待stdin上的活动,减少对stdin不必要的轮询

执行程序,发送
SIGUSR1
信号,然后键入 结果如下输出1:

A. T E s T
1) 在Linux上测试

不完全正确-我正在寻找一种方法,使“a”领先于“t”。这不应该是
terminal_settings.c_cc[VMIN]=1?是否在至少有1个字符可用时返回?
int insert_an_A = 0;
void handler(int sig) { insert_an_A = 1; }

void process_char(char c) { ... }

int main(int argc, char **argv) {
    int c;
    /* skip signal setup */
    while ((c = fgetc(stdin)) != EOF) {
        if (insert_an_A) {
            process_char('A');
            insert_an_A = 0;
        }
        process_char(c);
    }
}

void handler(int sig) {
   /* I know I shouldn't do this in a signal handler,
    * but this is modeled after the OP's code.
    */
   ungetc('A', stdin);
}

void wait_for_stdin() {
   fd_set fdset;
   FD_ZERO(&fdset);
   FD_SET(fileno(stdin),&fdset);
   select(1, &fdset, NULL, NULL, NULL);
}

void foo () {
   int key;
   struct termios terminal_settings;

   signal(SIGUSR1, handler);

   /* set the terminal to raw mode */
   tcgetattr(fileno(stdin), &terminal_settings);
   terminal_settings.c_lflag &= ~(ECHO|ICANON);
   terminal_settings.c_cc[VTIME] = 0;
   terminal_settings.c_cc[VMIN] = 0;
   tcsetattr(fileno(stdin), TCSANOW, &terminal_settings);

   for (;;) {
      wait_for_stdin();
      key = fgetc(stdin);
      /* terminate loop on Ctrl-D */
      if (key == 0x04) {
         break;
      }      
      if (key != EOF) {
         printf("%c\n", key);
      }
   }
}

A t e s t