这取决于您遵守的标准,但标准 C 不允许您做更多的事情,只能修改类型变量或从信号处理程序volatile sig_atomic_t
调用_Exit
(或abort()
或)。signal()
POSIX 宽松得多。您的信号处理程序中的代码充满了用户交互,甚至超出了 POSIX 允许的范围。通常,您希望您的信号处理函数小而苗条。
请注意,信号处理函数应为:
void trata_sinal_int(int signum)
{
这允许您在没有类型不匹配的强制转换或编译器警告的情况下进行编译。该signal()
函数可以在调用时将信号处理程序重置为默认行为;经典地,有必要在信号处理程序中恢复信号处理程序:
signal(signum, trata_sinal_int);
到目前为止,这一切都是非常通用和微不足道的。
当您键入 时Control-C,系统确实会返回到最初接收信号时的大致位置。但是,接下来会发生什么取决于它的位置(在处理程序内部必须非常小心的原因之一)。例如,如果它正在处理 内部的空闲列表指针malloc()
,它会返回那里,但如果你malloc()
在处理程序内部重新调用,那么所有的地狱都可能会崩溃。如果你在一个系统调用中,那么你的调用可能会被中断(返回一个错误指示和errno == EINTR
),或者它可能会从中断的地方继续。否则,它应该回到计算运行的地方。
这是您的代码(固定版本)内置到测试台中。该pause()
函数在返回之前等待一个信号。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
static void trata_sinal_int(int signum)
{
char op[2];
signal(signum, trata_sinal_int);
printf("\nTerminate? (y/n)\n");
scanf("%s", op);
if (op[0] == 'y')
{
printf("Bye Bye\n");
exit(0);
}
}
int main(void)
{
signal(SIGINT, trata_sinal_int);
for (int i = 0; i < 3; i++)
{
printf("Pausing\n");
pause();
printf("Continuing\n");
}
printf("Exiting\n");
return(0);
}
我真的应该指出,这scanf()
根本不是很安全。大小为 2 的缓冲区是缓冲区溢出的公开邀请。我也不是错误检查系统调用。
我在 BSD 衍生产品 Mac OS X 10.7.5 上进行了测试。很有signal()
可能在这个平台上不需要重置,因为 BSD 很久以前就引入了“可靠信号”(POSIX 之前)。
ISO/IEC 9899:2011 §7.14.1.1signal
功能
¶5 如果信号的出现不是调用abort
orraise
函数的结果,则如果信号处理程序引用具有静态或线程存储持续时间的任何对象,该对象不是无锁原子对象,则行为未定义,而不是通过赋值到声明为 的对象volatile sig_atomic_t
,或者信号处理程序调用标准库中的任何函数,而不是abort
函数、_Exit
函数、
quick_exit
函数或signal
函数,其第一个参数等于与导致调用的信号对应的信号编号处理程序。此外,如果对signal
函数的这种调用导致SIG_ERR
返回,则 errno 的值是不确定的。252)
252)如果任何信号由异步信号处理程序生成,则行为未定义。
引用quick_exit()
是 C2011 中的新内容;它们在 C1999 中不存在。
POSIX 2008
Signal Concepts部分非常详细地介绍了 POSIX 下的信号处理程序中允许和不允许的内容。