虽然 C++ 加入了异常机制来处理很多运行时错误, 但是异常机制的功效非常受限, 很多错误还没办法用原生异常手段捕捉, 比如整数除 0 错误. 下面这段代码
#include <iostream>
int main()
{
try {
int x, y;
std::cin >> x >> y;
std::cout << x / y << std::endl;
} catch (...) {
std::cerr << "attempt to divide integer by 0." << std::endl;
}
return 0;
}
使用信号
不过, 底层自然有底层的办法. 这得益于硬件体系中的中断机制. 简而言之, 当发生整数除 0 之类的错误时, 硬件会触发中断, 这时操作系统会根据上下文查出是哪个进程不给力了, 然后给这个进程发出一个信号. 某些时候也可以手动给进程发信号, 比如恼怒的用户发现某个程序卡死的时候果断 kill 掉这个进程, 这也是信号的一种.这次就不是 C 标准了, 而是 POSIX 标准. 它规定了哪些信号进程不处理也不会有太大问题, 有些信号进程想处理也是不行的, 还有一些信号是错误中断, 如果程序处理了它们, 那么程序能继续执行, 否则直接杀掉.
不过, 这些错误处理默认过程都是不存在的, 需要通过调用
signal
函数配置. 方法类似下面这个例子#include <csignal>
#include <cstdlib>
#include <iostream>
void handle_div_0(int)
{
std::cerr << "attempt to divide integer by 0." << std::endl;
exit(1);
}
int main()
{
if (SIG_ERR == signal(SIGFPE, handle_div_0)) {
std::cerr << "fail to setup handler." << std::endl;
return 1;
}
int x, y;
std::cin >> x >> y;
std::cout << x / y << std::endl;
return 0;
}
signal
接受两个参数, 分别是信号编号和信号处理函数. 成功设置了针对 SIGFPE
(吐槽: 为什么是浮点异常 FPE
呢?) 的处理函数 handle_div_0
, 如果再发生整数除 0 的惨剧, handle_div_0
就会被调用.handle_div_0
的参数是信号码, 也就是 SIGFPE
, 忽略它也行.