设为首页 加入收藏

TOP

嵌入式系统C编程之错误处理(五)
2015-01-22 20:57:58 来源: 作者: 【 】 浏览:47
Tags:嵌入式 系统 编程 错误 处理
境或操作系统可能发出信号(signal)事件,指示特定的 编程错误或严重事件(如除0或中断等)。这些信号本意并非用于错误捕获,而是指示与表示与正常程序流不协调的外部事件。
?
? ? ?为处理信号,需要使用以下信号相关函数:
?
#include
?
typedef void (*fpSigFunc)(int);
?
fpSigFunc signal(int signo, fpSigFunc fpHandler);
?
int raise(int signo);
?
? ? ?其中,参数signo是Unix系统定义的信号编号(正整数),不允许用户自定义信号。参数fpHandler是常量SIG_DFL、常量SIG_IGN或当接收到此信号后要调用的信号处理函数(signal handler)的地址。若指定SIG_DFL,则接收到此信号后调用系统的缺省处理函数;若指定SIG_ IGN,则向内核表明忽略此信号(SIGKILL和SIGSTOP不可忽略)。某些异常信号(如除数为零)不太可能恢复,此时信号处理函数可在程序终止前正确地清理某些资源。信号处理函数所收到的异常信息仅是一个整数(待处理的信号事件),这点与setjmp()函数类似。
?
? ? ?signal()函数执行成功时返回前次挂接的处理函数地址,失败时则返回SIG_ERR。信号通过调raise()函数产生并被处理函数捕获。
?
? ? ?以除零错误为例:
?
复制代码
?1 void fphandler(int dwSigNo)
?2 {
?3 ? ? printf("Exception is raised, dwSigNo=%d!\n", dwSigNo);
?4 }
?5 int main(void)
?6 {
?7 ? ? if(SIG_ERR == signal(SIGFPE, fphandler))
?8 ? ? {
?9 ? ? ? ? fprintf(stderr, "Fail to set SIGFPE handler!\n");
10 ? ? ? ? exit(EXIT_FAILURE);
11 ? ? }
12?
13 ? ? double fDividend = 10.0, fDivisor = 0.0;
14 ? ? if(0 == fDivisor)
15 ? ? {
16 ? ? ? ? raise(SIGFPE);
17 ? ? ? ? exit(EXIT_FAILURE);
18 ? ? }
19 ? ? printf("The quotient is %.2lf\n", fDividend/fDivisor);
20?
21 ? ? return 0;
22 }
复制代码
? ? ?执行结果为"Exception is raised, dwSigNo=8!"。
?
? ? ?若将被除数(Dividend)和除数(Divisor)改为整型变量:
?
复制代码
?1 int main(void)
?2 {
?3 ? ? if(SIG_ERR == signal(SIGFPE, fphandler))
?4 ? ? {
?5 ? ? ? ? fprintf(stderr, "Fail to set SIGFPE handler!\n");
?6 ? ? ? ? exit(EXIT_FAILURE);
?7 ? ? }
?8?
?9 ? ? int dwDividend = 10, dwDivisor = 0;
10 ? ? double fQuotient = dwDividend/dwDivisor;
11 ? ? printf("The quotient is %.2lf\n", fQuotient);
12?
13 ? ? return 0;
14 }
复制代码
? ? ?则执行后将循环输出"Exception is raised, dwSigNo=8!"。这是因为除0异常不可恢复。每次系统调用信号处理函数后,异常控制流还会返回除0指令继续执行。
?
? ? ?规避方法有两种:
?
? ? ?1) 将SIGFPE信号变成系统默认处理,即signal(SIGFPE, SIG_DFL)。
?
? ? ?此时执行输出为"Floating point exception"。
?
? ? ?2) 利用setjmp/longjmp跳过引发异常的指令:
?
复制代码
?1 jmp_buf gJmpBuf;
?2 void fphandler(int dwSigNo)
?3 {
?4 ? ? printf("Exception is raised, dwSigNo=%d!\n", dwSigNo);
?5 ? ? longjmp(gJmpBuf, 1);
?6 }
?7 int main(void)
?8 {
?9 ? ? if(SIG_ERR == signal(SIGFPE, SIG_DFL))
10 ? ? {
11 ? ? ? ? fprintf(stderr, "Fail to set SIGFPE handler!\n");
12 ? ? ? ? exit(EXIT_FAILURE);
13 ? ? }
14?
15 ? ? int dwDividend = 10, dwDivisor = 0;
16 ? ? if(0 == setjmp(gJmpBuf))?
17 ? ? {
18 ? ? ? ? double fQuotient = dwDividend/dwDivisor;
19 ? ? ? ? printf("The quotient is %.2lf\n", fQuotient);
20 ? ? }
21 ? ? else
22 ? ? {
23 ? ? ? ? printf("The divisor cannot be 0!\n");
24 ? ? }
25?
26 ? ? return 0;
27 }
复制代码
? ? ?注意,在信号处理程序中还可使用sigsetjmp/siglongjmp函数进行非局部跳转。相比setjmp函数,sigsetjmp函数增加一个信号屏蔽字参数。
?
?
?
三 ?错误处理
3.1 终止(abort/exit)
? ? ?致命性错误无法恢复,只能终止程序。例如,当空闲堆管理程序无法提供可用的连续空间时(调用malloc返回NULL),用户程序的健壮性将严重受损。若恢复的可能性渺茫,则最好终止或重启程序。
?
? ? ?标准C库提供exit()和abort()函数,分别用于程序正常终止和异常终止。两者都不会返回到调用者中,且都导致程序被强行结束。
?
? ? ?exit()及其相似函数原型声明如下:
?
#include
?
void exit(int status);
?
void _Exit(int status);
?
#include
?
void _exit(int status);
?
? ? ?其中,exit和_Exit由ISO C说明,而_exit由Posix.1说明。因此使用不同的头文件。
?
? ? ?ISOC定义_Exit旨在为进程提供一种无需运行终止处理程序(exit handler)或信号处理程序(signal handler)而终止的方法,是否冲洗标准I/O流则取
首页 上一页 2 3 4 5 6 7 8 下一页 尾页 5/8/8
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Objective-C中的继承和多态 下一篇objective-c 复制对象

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: