C不提供对错误处理的直接支持(也称为异常处理)。按照惯例,程序员应该首先防止错误发生,并测试函数的返回值。例如,-1和NULL分别用于几个函数,如socket()(Unix套接字编程)或malloc(),以指示程序员应该注意的问题。在最糟糕的情况下,存在不可避免的错误并且无法从中恢复,C程序员通常会尝试记录错误并“正常”终止程序。
在包含<errno.h>之后,程序可以访问一个名为“errno”的外部变量 – 该文件来自某些操作系统中可能出现的错误的定义(例如Linux – 在这种情况下,定义是在include / asm-generic / errno.h)当程序要求资源时。这样的变量索引错误描述可由函数’strerror(errno)’访问。
以下代码测试库函数malloc的返回值,以查看动态内存分配是否正确完成:
#include <stdio.h> / * perror * / #include <errno.h> / * errno * / #include <stdlib.h> / * malloc,free,exit * / int main (void ) { / *指向char的指针,请求动态分配2,000,000,000个 *存储元素(声明为 * unsigned long int 类型的整数常量)。(如果你的系统内存少于2 GB *,那么对malloc的调用将失败。) * / char * ptr = malloc (2000000000UL ); if (ptr == NULL ) { perror (“malloc failed” ); / *在这里你可能想要退出程序或补偿 你没有2GB可用 * / } 否则 { / *此后的其余代码可以假设 成功分配 了2,000,000,000个*字符... * / 免费(ptr ); } 退出(EXIT_SUCCESS ); / *退出程序* / }
上面的代码片段显示了使用库函数malloc的返回值来检查错误。许多库函数都有返回值来标记错误,因此应该由精明的程序员检查。在上面的代码片段中,从malloc返回的NULL指针表示分配错误,因此程序退出。在更复杂的实现中,程序可能会尝试处理错误并尝试从失败的内存分配中恢复。
防止零除错误
C程序员常见的缺陷是在除法命令之前没有检查除数是否为零。以下代码将产生运行时错误,在大多数情况下,退出。
int dividend = 50 ; int divisor = 0 ; int 商; quotient = (dividend / divisor ); / *这会产生运行时错误!* /
由于超出本文档范围的原因,您必须检查或确保除数从不为零。或者,对于* nix进程,您可以通过阻止SIGFPE信号来阻止操作系统终止进程。
下面的代码通过在分割之前检查除数是否为零来解决此问题。
#include <stdio.h> / *表示fprintf和stderr * / #include <stdlib.h> / * for exit * / int main ( void ) { int dividend = 50 ; int divisor = 0 ; int 商; if (divisor == 0 ) { / *处理此错误的示例。将消息写入stderr,然后 *以失败退出。 * / fprintf (stderr , “除以零!中止...... \ n ” ); 退出(EXIT_FAILURE ); / *表示失败。* / } quotient = dividend / divisor ; 退出(EXIT_SUCCESS ); / *表示成功。* / }
信号
在某些情况下,环境可以通过提高信号来响应C中的编程错误。信号是由主机环境或操作系统引发的事件,用于指示已发生特定错误或严重事件(例如,除以零,中断等)。但是,这些信号并不意味着用作错误捕捉; 它们通常表示会干扰正常程序流程的关键事件。
要处理信号,程序需要使用signal.h头文件。需要定义信号处理程序,然后调用signal()函数以允许处理给定信号。在代码中引发异常的一些信号(例如,除以零)不太可能允许程序恢复。这些信号处理程序将需要确保在程序终止之前正确清理某些资源。
此示例创建信号处理程序并引发信号:
#include <signal.h> #include <stdio.h> #include <stdlib.h> static void catch_function (int signal ) { puts (“Interactive attention signal caught。” ); } int main (void ) { if (signal (SIGINT , catch_function ) == SIG_ERR ) { fputs (“设置信号处理程序时发生错误。\ n ” , stderr ); 返回 EXIT_FAILURE ; } puts (“提高交互式注意信号。” ); if (raise (SIGINT ) != 0 ) { fputs (“引发信号错误。\ n “ , stderr ); 返回 EXIT_FAILURE ; } puts (”退出。“ ); 返回 0 ; }
setjmp
该setjmp的函数可用于模拟其他编程语言的异常处理功能。第一次调用setjmp提供了返回给定函数的引用点,只要包含setjmp()的函数没有返回或退出,它就是有效的。对longjmp的调用会导致执行返回到关联的setjmp调用点。
#include <stdio.h> #include <setjmp.h> jmp_buf test1 ; 空隙 tryjump () { longjmp的(TEST1 , 3 ); } int main (void ) { if (setjmp (test1 )== 0 ) { printf (“setjmp()return 0.” ); tryjump (); } else { printf (“setjmp从longjmp函数调用返回。” ); } }
当setjmp从longjmp调用返回时,非易失性变量的值可能会被破坏。
虽然setjmp()和longjmp()可用于错误处理,但如果可能,通常最好使用函数的返回值来指示错误。
猜你想读:《C编程.中级C》5.流I/O