- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在编写名为“Headfirst C”的 C 文本中的一些示例代码。我编写了一个演示信号处理的练习应用程序,并在完成本章后决定尝试一下。我是一名工程师,曾经在 LabVIEW(高度并发和直观的事件处理功能)中工作,所以我对使用警报和信号处理程序来生成周期性事件很感兴趣。我的问题是:
在以下示例代码中,丢弃位于标准输入中的可变数量的用户输入的正确方法或最佳实践是什么?我已经将这个小应用程序编写为演示,3 秒警报会触发恼人的“你好!”中断 fgets 调用的消息。然而,我注意到的是,如果用户在打字过程中被打断,当他最终按下回车键时,任何输入的文本(无论是否被打断)都会被回显。我想丢弃在用户按下回车键之前被打断的任何东西。
//Sample Program - Signal Handling & Alarms
//Header Includes
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
//Function Declarations
//Handler Functions
void diediedie(int sig);
void howdy(int sig);
//Handler Register Function
int catchSignal(int signum, void(*handler)(int));
//Variable declarations
//Declare interrupted flags
static int interrupted = 0;
//Program entrypoint
int main() {
//Register interrupt hander, catch errors
if(catchSignal(SIGINT, diediedie) == -1) {
fprintf(stderr, "Could not register interrupt handler");
exit(2);
}
//Register alarm handler, catch errors
if(catchSignal(SIGALRM, howdy) == -1) {
fprintf(stderr, "Could not register alarm handler");
exit(2);
}
//Create initial alarm trigger
alarm(3);
//Do something stupid while waiting for signals
char name[30];
printf("Enter your name: ");
//Keep waiting for user input even if interrupted by alarm signal
while(1) {
fgets(name, 30, stdin);
if(interrupted) {
// reset interrupted flag
interrupted = 0;
// ***** ADD CODE TO DISCARD INTERRUPTED INPUT HERE ******
}
else {
//echo user input and break out
printf("Hello %s\n", name);
break;
}
}
//end program
return 0;
}
//interrupt handler definition
void diediedie(int sig) {
//write some stuff, exit program
puts("Goodbye world!");
exit(1);
}
//alarm handler definition
void howdy(int sig) {
//set interrupted flag
interrupted = 1;
//write some annoying message
puts("howdy!");
//set another alarm trigger
alarm(3);
//**** COULD STDIN BE FLUSHED HERE? ****
}
//signal handler registration function definition
int catchSignal(int signum, void(*handler)(int)) {
//register handler
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
return sigaction(signum, &action, NULL);
}
在警报处理程序中是否适合执行此清除操作?请注意表明我对正确代码位置的想法的注释。
我考虑了以下几点:
while(getchar() != EOF) {}
我也想知道,当 fgets 等待用户输入并引发 SIGALRM 时会发生什么?该功能是否已终止?我观察到,如果我不包括 while 循环来检查中断标志并做出适当响应,程序将完成 fgets,在屏幕上转储一些垃圾(我假设 stdin 的当前状态?)并结束程序。
感谢您的任何建议!
最佳答案
在 Unix 中,信号处理程序与您的代码一起出现在带外。如果信号发生在阻塞系统调用的中间,系统调用将退出,errno
设置为 EINTR。但我相信 fgets()
正在为您处理此中断并继续进行而不会将控制权返回给您。
如果您使用的是基于 Unix 的操作系统并从命令行键入输入,那么这里真正发生的是您正在以熟化模式从终端读取数据。在按下回车之前,您的程序不会从 TTY 获取任何数据。您需要将终端设置为“原始”模式。以下是如何将其与您的代码集成的示例:
//Sample Program - Signal Handling & Alarms
//Header Includes
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <termios.h>
//Function Declarations
//Handler Functions
void diediedie(int sig);
void howdy(int sig);
//Handler Register Function
int catchSignal(int signum, void(*handler)(int));
//Variable declarations
//Declare interrupted sa_flags
static int interrupted = 0;
static struct termios save_termios;
//Program entrypoint
int main() {
struct termios buf;
int fd = 1;
// This is derived from from Stevens, "Advanced Programming in the UNIX Environment"
if (tcgetattr(fd, &save_termios) < 0) /* get the original state */
return -1;
buf = save_termios;
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* echo off, canonical mode off, extended input
processing off, signal chars off */
buf.c_iflag |= BRKINT | ICRNL;
/* SIGINT on BREAK, CR-toNL on */
buf.c_cflag &= ~(CSIZE | PARENB);
/* clear size bits, parity checking off */
buf.c_cflag |= CS8;
/* set 8 bits/char */
buf.c_oflag &= ~(OPOST);
/* output processing off */
buf.c_cc[VMIN] = 1; /* 1 byte at a time */
buf.c_cc[VTIME] = 0; /* no timer on input */
if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
return -1;
//Register interrupt hander, catch errors
if(catchSignal(SIGINT, diediedie) == -1) {
fprintf(stderr, "Could not register interrupt handler");
exit(2);
}
//Register alarm handler, catch errors
if(catchSignal(SIGALRM, howdy) == -1) {
fprintf(stderr, "Could not register alarm handler");
exit(2);
}
//Create initial alarm trigger
alarm(3);
//Do something stupid while waiting for signals
char name[30];
printf("Enter your name: ");
//Keep waiting for user input even if interrupted by alarm signal
char nextchar = 0;
char *p;
p = name;
while(nextchar != '\n') {
nextchar = fgetc(stdin);
if (interrupted) {
// reset interrupted flag
interrupted = 0;
//Discard interrupted input by reseting 'p' to the start of the buffer
p = name;
*p = 0;
continue;
}
if (nextchar == '\n') {
*p = 0;
fputc('\r', stdout);
fputc('\n', stdout);
break;
}
// You'll have to handle some characters manually to emulate what the
// terminal does, or you could filter them out using a function like isprint()
//
if (nextchar == 127) {
// *** handle backspace
if (p > name) {
p--;
}
// TODO: To handle this right you'll have to backup the cursor on the screen
} else {
*p = nextchar;
p++;
}
fputc(nextchar, stdout);
// Handle buffer overflow
if (p-name == sizeof(name) - 1) {
*p = 0;
break;
}
}
// echo user input
printf("Input is: %s\r\n", name);
tcsetattr(1, TCSAFLUSH, &save_termios);
}
//interrupt handler definition
void diediedie(int sig) {
//write some stuff, exit program
puts("Goodbye world!");
tcsetattr(1, TCSAFLUSH, &save_termios);
exit(1);
}
//alarm handler definition
void howdy(int sig) {
//set interrupted flag
interrupted = 1;
//write some annoying message
puts("howdy!");
//set another alarm trigger
alarm(3);
}
// signal handler registration function definition
int catchSignal(int signum, void(*handler)(int)) {
//register handler
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
return sigaction(signum, &action, NULL);
}
注意需要保存原来的终端设置,在程序退出前恢复!如果遇到麻烦,您可能会破坏终端设置。从命令行使用 reset
或 stty sane
来恢复正常的终端设置。有关 termios 数据结构的更多信息,请参阅手册页。
您还可以使用像 ncurses 这样的库处理原始输入。
关于c - 在 C 中安全丢弃可变长度的标准输入字符的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29451133/
我有一个测试即将进行,我想澄清两个有关参数的问题。 在我的笔记中指出,将参数传递给函数的推荐方法是使用“按引用传递” const type& x; // for "in" parameters
当我通过 OMG 2.5(Beta)推广的 UML 规范阅读以下概念时: in: Indicates that Parameter values are passed in by the caller
我试图在用户按下 Enter 时触发一个函数。我将此输入设置为只读的原因是限制用户在填充值后修改输入中的值。 该值来自将在点击属性中触发的弹出窗口。问题是 keyup.enter 没有触发该输入。 代
我在jQuery中使用模式弹出窗口控件,该弹出窗口具有由jQuery Tokenize输入插件提供动力的输入文本。问题是,当我在模式弹出文本框中键入内容时, token 化插件的搜索结果显示为隐藏在弹
我有一个问题。当我选中复选框时,系统工作正常,总值发生变化,但一旦我修改文本输入,它就会变为 0。我需要将此文本框输入排除在更改值之外。 这是 html: $15000 $
我正在努力让它发挥作用,但还是有些不对劲。 我想用 CSS 设置提交按钮的样式以匹配我已有的按钮。 风格: input[type="button"], input[type="submit"], b
import java.util.*;; public class selection { Scanner in=new Scanner(System.in); private
这可能是一个非常菜鸟的问题。假设我有一个带宽限制为 100MB/s 的网卡,那么输入/输出带宽是否有可能达到该限制 同时 ?或者我会在任何时候遇到这个不等式:in bandwidth + out ba
看着这个问题,Fill immutable map with for loop upon creation ,我很好奇是什么this表示在 Map(1 -> this) . scala> Map(1
我有这样的东西 一个 乙 问? 是或否 数字 数字或零 我想做的是: 如果 B1 = “Y”,则让用户在 B2 中输入一个数字。 如果 B1 = “N”,则将 B2 中的值更改为零,并且不允许用户在
我有一个包含许多列的表,我想添加 input标题单元格内的字段,但我希望输入适合根据正文内容的宽度。 这是没有 input 的样子领域: 这就是 input 的样子领域: 可以看出,像“index”和
关于为 FTP 客户端设置传出和传入文件夹,您遵循哪些最佳实践(如果有)?我们通常使用“outgoing”和“incoming”,但无论你如何表述方向,它都可以有两种解释方式,具体取决于名称相对于哪一
我正在尝试“求解”给定 d 的 Pell 方程:x^2 - d * y^2 = 1,或者至少我想得到最小的 x > 0 来求解方程。到目前为止,一切都很好。这是我的 Haskell 代码 minX :
我是VS Code的新手,可以使用Ctrl + Enter将代码运行到python交互式窗口中。我希望光标自动移动到下一行,因此我可以逐行浏览代码。 能做到吗? 最佳答案 如this blog pos
我正在创建一个 bool 值矩阵/二维数组,并且我想为 dategrid 推断一种不仅仅是“ANY”的类型。 let yearRange = [2000,2001,2002,2003,2004]; l
我有两个排序的列表,例如 a = [1, 4, 7, 8] b = [1, 2, 3, 4, 5, 6] 我想知道a中的每个项目是否在b中。对于上面的示例,我想找到 a_in_b = [True, T
菜鸟警报 这很奇怪 - 当我编写以下代码时,尝试在 AngularJS 中创建自定义指令: myModule.directive('myTab', function(){ console.lo
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
假设我正在使用 gdscript 静态类型,并且对于一个函数参数,我事先不知道我会得到什么。这就是 python 中 typing.Any 的作用。如何使用 gdscript 做到这一点? 似乎 Va
我使用 dropzone 上传多个图像,并且工作正常,直到我想为每个图像插入品牌和网址。 我遇到的唯一问题是,当我要从输入字段获取值时,我会从服务器获取来自字段(品牌、网址)的未定义值,但如果我使用静
我是一名优秀的程序员,十分优秀!