sigfpe(信号编号8)是算术异常信号,不仅触发整数除零,还涵盖浮点溢出等;但ieee 754浮点除零默认不产生该信号,需显式启用。

Linux中捕获SIGFPE(算术异常)信号,核心是用signal()或更健壮的sigaction()注册自定义处理函数,并在函数中识别具体错误类型。但要注意:SIGFPE默认终止进程+core dump,且它不只对应“除零”,还涵盖浮点溢出、无效操作等;更重要的是,**整数除零在x86-64 Linux上通常触发SIGFPE,而IEEE 754浮点除零(如1.0/0.0)默认不产生信号,而是返回±∞或NaN**。
注册SIGFPE处理函数
使用signal()是最简方式,适合快速验证:
- 包含头文件:
#include <signal.h></signal.h> - 定义处理函数,参数为
int sig(信号编号),无需额外参数(若需访问寄存器状态,须用sigaction配合SA_SIGINFO) - 调用
signal(SIGFPE, handler)完成注册
示例代码片段:
void fpe_handler(int sig) {
write(STDERR_FILENO, "Caught SIGFPE!\n", 16);
// 不建议在此调用printf等非异步信号安全函数
_exit(1); // 安全退出,避免重入问题
}
int main() {
signal(SIGFPE, fpe_handler);
int a = 5, b = 0;
volatile int c = a / b; // 触发整数除零 → SIGFPE
return 0;
}
区分不同FPE错误类型(需sigaction)
signal()无法获取错误细节;要判断是除零、溢出还是非法操作,必须用sigaction并启用SA_SIGINFO标志:
- 声明处理函数原型为
void handler(int sig, siginfo_t *info, void *ucontext) - 检查
info->si_code:常见值有FPE_INTDIV(整数除零)、FPE_INTOVF(整数溢出)、FPE_FLTDIV(浮点除零)等 - 注意:
si_code为SI_USER时说明信号由kill()等软件发送,非硬件异常
关键限制与注意事项
SIGFPE捕获有重要边界条件,忽略会导致行为不符合预期:
-
浮点运算默认不发信号:
double x = 1.0 / 0.0;结果是+inf,不触发SIGFPE;需用feenableexcept(FE_DIVBYZERO)(需<fenv.h></fenv.h>)显式启用浮点异常报告 -
整数除零行为依赖架构和编译器:GCC默认生成会触发SIGFPE的指令,但加
-fno-trapping-math可能抑制;-mcheck-zero-division选项可强制检查(仅部分GCC版本支持) -
处理函数内只能调用异步信号安全函数:如
write()、_exit()、siglongjmp();禁用printf、malloc、pthread_mutex_lock等 -
不要试图从SIGFPE中恢复继续执行原指令:CPU状态已破坏,强行
longjmp回出错点极易导致未定义行为
替代思路:预防优于捕获
对关键计算,主动检查比依赖信号更可靠:
- 整数除法前判断除数是否为零
- 浮点运算后用
isinf()、isnan()检测结果有效性 - 启用浮点异常:调用
feenableexcept(FE_ALL_EXCEPT),再配合SIGFPE处理 - 调试阶段开启
ulimit -c unlimited,配合core dump分析根本原因











