news 2026/6/10 11:29:58

C语言中嵌套捕获异常

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言中嵌套捕获异常

在C++中我们可以使用try/catch来捕获异常,但是C语言中没有这样的关键字,只有setjmplongjmp函数,它们的常规用法是先设置信号捕获函数,再调用setjmp,在信号捕获函数中调用longjmp,如果出现异常则会跳到setjmp后面:

#include<setjmp.h>#include<signal.h>#include<stdio.h>jmp_buf buf;voidsig(ints){switch(s){caseSIGSEGV:caseSIGINT:caseSIGFPE:(void)signal(s,sig);longjmp(buf,1);break;default:break;}}intmain(intargc,char*argv[]){(void)signal(SIGINT,sig);(void)signal(SIGFPE,sig);(void)signal(SIGSEGV,sig);if(setjmp(buf)==0){int*p=nullptr;*p=0;}else{printf("exception\n");}

我们可以使用宏来模拟try,catch

#defineTRYif(setjmp(buf)==0){#defineCATCH\}\else

这样就可以写成下面的形式了:

TRY{}CATCH{}

目前这种形式不支持嵌套捕获,比如:

TRY{TRY{}CATCH{}//如果这里出现异常,就不能捕获}CATCH{}

要支持捕获,也很简单,把jmp_buf设置成数组,再使用一个变量来记录深度,使用一次TRY则加1,CATCH时减1即可:

jmp_buf buf[256]={};uint8_tdepth=0;#defineTRYif(setjmp(buf[depth++])==0){#defineCATCH\--depth;\}\elsevoidsig(ints){switch(s){caseSIGSEGV:caseSIGINT:caseSIGFPE:(void)signal(s,sig);longjmp(buf[--depth],1);break;default:break;}}

测试代码:

#include<setjmp.h>#include<signal.h>#include<stdint.h>#include<stdio.h>jmp_buf buf[256]={};uint16_tdepth=0;#defineTRYif(setjmp(buf[depth++])==0){#defineCATCH\--depth;\}\elsevoidsegv(){int*v=nullptr;*v=1;printf("%p\n",v);}voiddiv0(){intv=0;printf("%d\n",1/v);}voidsig(ints){switch(s){caseSIGSEGV:caseSIGINT:caseSIGFPE:(void)signal(s,sig);longjmp(buf[--depth],1);break;default:break;}}voidtest(){TRY{TRY{segv();}CATCH{printf("SIGSEGV exception\n");}div0();}CATCH{printf("SIGFPE exception\n");}}intmain(intargc,char*argv[]){(void)signal(SIGINT,sig);(void)signal(SIGFPE,sig);(void)signal(SIGSEGV,sig);TRY{test();}CATCH{printf("test exception\n");}printf("ok\n");return0;}

如果是使用的VC编译器和调试器,在除0的地方会直接断下来,并不会继续执行,所以触发不了SIGFPE信号,这是由于SEH异常机制导致,如果想要实现与GCC一样的行为,即POSIX行为,则需要拦截SEH,手动触发SIGFPE信号:

#if_MSC_VER#include<windows.h>LONG WINAPIseh_handler(EXCEPTION_POINTERS*e){if(e->ExceptionRecord->ExceptionCode==EXCEPTION_INT_DIVIDE_BY_ZERO){raise(SIGFPE);returnEXCEPTION_CONTINUE_EXECUTION;}returnEXCEPTION_CONTINUE_SEARCH;}#endif

再调用:

#if_MSC_VERAddVectoredExceptionHandler(1,seh_handler);#endif

完整代码:

#include<setjmp.h>#include<signal.h>#include<stdint.h>#include<stdio.h>#if_MSC_VER#include<windows.h>LONG WINAPIseh_handler(EXCEPTION_POINTERS*e){if(e->ExceptionRecord->ExceptionCode==EXCEPTION_INT_DIVIDE_BY_ZERO){raise(SIGFPE);returnEXCEPTION_CONTINUE_EXECUTION;}returnEXCEPTION_CONTINUE_SEARCH;}#endifjmp_buf buf[256]={};uint16_tdepth=0;#defineTRYif(setjmp(buf[depth++])==0){#defineCATCH\--depth;\}\elsevoidsegv(){int*v=0;*v=1;printf("%p\n",v);}voiddiv0(){intv=0;printf("%d\n",1/v);}voidsig(ints){switch(s){caseSIGSEGV:caseSIGINT:caseSIGFPE:(void)signal(s,sig);longjmp(buf[--depth],1);break;default:break;}}voidtest(){TRY{TRY{segv();}CATCH{printf("SIGSEGV exception\n");}div0();}CATCH{printf("SIGFPE exception\n");}}intmain(intargc,char*argv[]){#if_MSC_VERAddVectoredExceptionHandler(1,seh_handler);#endif(void)signal(SIGINT,sig);(void)signal(SIGFPE,sig);(void)signal(SIGSEGV,sig);TRY{TRY{TRY{segv();}CATCH{printf("SIGSEGV exception\n");}div0();}CATCH{printf("SIGFPE exception\n");}test();}CATCH{printf("test exception\n");}printf("ok\n");return0;}

如果对你有帮助,欢迎点赞收藏!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 14:27:42

Java毕设项目:基于MyBatis的在线车辆租赁信息管理系统的设计与实现(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/10 11:36:07

Plecs中三相电源参数设计详解

Plecs电路仿真时,经常需要用到的是单相电源和三相电源,使用过程中经常与常用的电压220V或者380V搞混,导致设计出现错误。 图中的电源参数为三相电的峰值311V= 220*1.414 V,并非有效值。 在PLECS的三相电压源(Voltage Source AC (3-Phase))中,Amplitude 参数指的是正弦…

作者头像 李华
网站建设 2026/6/4 18:34:14

Java毕设项目:基于SpringBoot的电脑维修工单管理系统的设计与实现(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/5 10:36:33

对话小水智能CEO孙雪峰:创业者如何在细分赛道逆袭大厂

作者&#xff5c;周雅 来源&#xff5c;《原点Talk》 播客录制灯光亮起前&#xff0c;孙雪峰习惯性地调整了一下坐姿。 兼职中欧校友协会的会长的他&#xff0c;见过无数商业计划书在咖啡馆里诞生&#xff0c;又在资本寒冬中消逝。但在《原点Talk》的演播室里&#xff0c;孙雪峰…

作者头像 李华
网站建设 2026/6/10 12:32:07

AI原生应用与差分隐私的协同发展之路

AI原生应用与差分隐私的协同发展之路 关键词&#xff1a;AI原生应用、差分隐私、隐私保护、数据安全、AI伦理、协同架构、隐私计算 摘要&#xff1a;本文将深入探讨AI原生应用与差分隐私的协同发展逻辑。通过生活化的类比和技术原理解析&#xff0c;我们将揭示&#xff1a;为何…

作者头像 李华
网站建设 2026/5/31 7:40:19

Vivado无源代码自定义IP核封装方法(IP核不含源代码)

Vivado无源代码自定义IP核封装前言一. 使用EDF网表文件封装自定义IP核二. 使用DCP网表文件封装自定义IP核在进行FPGA开发时,如果不希望将源代码交给别人时,有两种方式: 一种方法是将自己的源代码生成网表文件,交出网表文件即可,网表文件又分为DCP网表和EDF网表;另一种方法是将自…

作者头像 李华