C错误异常处理,异常处理
预处理器标识#error的目的是什么啊? 指令 用途 # 空指令,无任何效果 #include 包含一个源代码文件 #define 定义宏 #undef 取消已定义的宏 #if 如果给定条件为真,则编译下面代码 #ifdef 如果宏已经定义,则编译下面代码 #ifndef 如果宏没有定义,则编译下面代码 #elif 如果前面的#if给定条件不为真,当前条件为真,则编译下面代码 #endif 结束一个#if……#else条件编译块 #error 停止编译并显示错误信息 #error是放到异常代码段处理才写的。。比如说。if else 如果你的程序进了else 就表示出错了。 那么else里面可以打印一下错误信息。方便你自己调试用。 定义#if #else 等预定义的时候做提示,一般放在*.H头文件中。 #error预处理指令的作用是,编译程序时,只要遇到#error就会生成一个编译错误提示消息,并停止编译。其语法格式为: #error error-message 注意,宏串error-message不用双引号包围。遇到#error指令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。系统所支持的error-message请查找相关信息获得!
assert()函数用法总结
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
#include <assert.h>void assert( int expression );
assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。请看下面的程序清单badptr.c:
#include <stdio.h>#include <assert.h>#include <stdlib.h>int main( void ){ FILE *fp; fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件 assert( fp ); //所以这里不会出错 fclose( fp ); fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败 assert( fp ); //所以这里出错 fclose( fp ); //程序永远都执行不到这里来 return 0;}
[root@localhost error_process]# gcc badptr.c
[root@localhost error_process]# ./a.out
a.out: badptr.c:14: main: Assertion `fp' failed.
已放弃使用assert()的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:
#include <stdio.h>#define NDEBUG#include <assert.h>
用法总结与注意事项:
1)在函数开始处检验传入参数的合法性如:
int resetBufferSize(int nNewSize){ //功能:改变缓冲区大小, //参数:nNewSize 缓冲区新长度 //返回值:缓冲区当前长度 //说明:保持原信息内容不变 nNewSize<=0表示清除缓冲区 assert(nNewSize >= 0); assert(nNewSize <= MAX_BUFFER_SIZE); ...}
2)每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败,如:
不好:
assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);
好:
assert(nOffset >= 0);assert(nOffset+nSize <= m_nInfomationSize);
3)不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题,如:
错误:
assert(i++ < 100);
这是因为如果出错,比如在执行之前i=100,那么这条语句就不会执行,那么i++这条命令就没有执行。
正确:
assert(i < 100); i++;
4)assert和后面的语句应空一行,以形成逻辑和视觉上的一致感。
5)有的地方,assert不能代替条件过滤。
assert() 宏用法 注意:assert是宏,而不是函数。在C的assert.h 头文件中。 assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义: #include <assert.h> void assert( int expression ); assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么它先向标准错误流stderr打印一条出错信息,然后通过调用 abort 来终止程序运行;否则,assert()无任何作用。宏assert()一般用于确认程序的正常操作,其中表达式构造无错时才为真值。完成调试后,不必从源代码中删除assert()语句,因为宏NDEBUG有定义时,宏assert()的定义为空。[] 请看下面的程序清单badptr.c: #include <stdio.h> #include <assert.h> #include <stdlib.h> int main( void ) { FILE *fp; fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件 assert( fp ); //所以这里不会出错 fclose( fp ); fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败 assert( fp ); //所以这里出错 fclose( fp ); //程序永远都执行不到这里来 ; } [root@localhost error_process]# gcc badptr.c [root@localhost error_process]# ./a.out a.: main: Assertion `fp' failed. 已放弃 使用assert的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。 在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下: #include <stdio.h> #define NDEBUG #include <assert.h> 用法总结与注意事项: )在函数开始处检验传入参数的合法性 如: int resetBufferSize(int nNewSize) { //功能:改变缓冲区大小, //参数:nNewSize 缓冲区新长度 //返回值:缓冲区当前长度 //说明:保持原信息内容不变 nNewSize<=0表示清除缓冲区 assert(nNewSize >= ); assert(nNewSize <= MAX_BUFFER_SIZE); ... } )每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败 不好: assert(nOffset>= && nOffset+nSize<=m_nInfomationSize); 好: assert(nOffset >= ); assert(nOffset+nSize <= m_nInfomationSize); )不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题 错误: assert(i++ < ) 这是因为如果出错,比如在执行之前i=,那么这条语句就不会执行,那么i++这条命令就没有执行。 正确: assert(i < ) i++; )assert和后面的语句应空一行,以形成逻辑和视觉上的一致感 )有的地方,assert不能代替条件过滤 注意:当对于浮点数: #include<assert.h> // float pi=3.14; // assert(pi==3.14); // float pi=3.14f; assert (pi==3.14f); --------------------------------------------------------- 在switch语句中总是要有default子句来显示信息(Assert)。 int number = SomeMethod(); switch(number) { : Trace.WriteLine("Case 1:"); break; : Trace.WriteLine("Case 2:"); break; default : Debug.Assert(false); break; }
C语言错误处理策略 今天写程序时,发现自己平时不爱做异常处理。(C语言的异常处理比起java的来总觉得好费劲啊~) 上网google了一下看见了一位大牛的解释,好厉害,膜拜一下 . 返回值方式:用函数的返回值标志函数是否执行成功。比如成功返回1,失败返回0。这种方式的好处是简单方便,而且不影响效率,保持了c语言的高效率。但是仍然有问题,一个问题是代码可读性的问题,如果每个函数都有这样的返回值的话,为了保持程序的正确运行,我们必须对每个函数进行正确性验证,就是在调用函数的时候检查他的返回值,这样程序代码很大一部分就可能花费在错误处理上。第二个问题就是函数的返回值冲突的问题。假设strlen函数也可能会出错,使用这种错误处理策略他的返回值应该标志它是否执行成功,但是函数计算的字符串的长度值如何自然地传递出来?最后一个问题可能是最重要的:它不强制你处理错误,而且在不进行处理的情况下,程序仍然能够运行,但结果是不可预知的。 返回值可以判定正确错误,或则增加一些简单的错误类型判定. 其缺点在于一旦函数修改后返回值回有变化的话就很麻烦,当然最重要的还在于无法明确获知错误信息;当然优势很明显,那就是简单. 总的来说一般返回值只是做简单的正确错误判定,而不能作为获知具体错误的手段. 这里还涉及一个使用习惯的问题,一般来说返回0位正确,非0为错误,但是也有颠倒的,这里和个人编码习惯有关,所以要特别注意就是了. . 全局errno方式:就是在出现错误的时候,将错误代码记录到一个全局变量errno中。比如waitpid()函数在被信号中断的情况下,将errno设置为EINTR(一宏定义常量)。这种方式解决了返回值方式遇到的返回值冲突问题,而且效率方面也是非常令人愉悦的。但是它要求用户在调用函数后检查errno的值,这种保证是脆弱的,程序仍然有可能在不处理那些errno的情况下”安然”地运行,导致未定义的结果。另一个问题出在多线程方面,errno不是线程安全的,多个线程操作同一个errno会造成混乱。 在windows下errno是线程安全的,不知道linux下是线程安全还是进程安全. 在ANSI C中有定义一些基本的errno,并且操作系统也会扩展一部分,但是依然无法改变其对错误描述的匮乏. 相对windows下GetLastError组合FormatMessage的组合则显得丰满很多,可以详细了解错误信息. 作为一种补充的方式,这种全局错误代码的方式也是相当不错的,和第1种方法搭配处理可以解决90%以上的错误处理. 这里特别要推荐在windows下开发,处理错误应该尽量使用GetLastError组合FormatMessage,而非errno. . 错误封装:就是将每个有错误返回值的函数分别用一个函数包起来,比如waitpid()函数可以封装成Waitpid()(首字母大写),在这个函数中处理相应的错误。这种错误处理方法可以很好的解决很多问题,应该说效果很好,但是有几个方面需要商榷,一是,并不是每个函数的错误都以一种方式进行处理,另一方面,听说c语言的函数调用开销相对很高,在函数外面再包上一层会影响性能。 封装向来都是由针对性的,对于错误处理,封装的难度非常大,通用型的封装是不适用的,更多的时候是要根据具体业务来处理的. 举例个不是很恰当的例子,比如用CreateFile去打开一个文件,A程序如果打开失败就退出,那么也许可以直接封装一个函数MyOpenFile产生错了,就呼叫exit退出程序. 但是B程序去要在打开错误后尝试新建一个文件,那么MyOpenFile在这里就不适用了. 当然一些基础功能的系统函数还是可以尝试进行通用的错误封装,例如内存操作、内核对象操作等,因为这些错误产生后基本上就只能做同一件事情了,具体封装方法就是呼叫一个全局的资源清理函数,然后exit. 全局清理函数为一个引出的函数指针,由具体的AP来实现,这样就不需要担心资源在退出后无法被释放的问题了. 至于说函数呼叫的开销,除非你现在是在做MCU级别的开发,否则请丢掉这个想法吧. 何况错误处理有一个原则,是允许大部分错误产生后消耗更多的时间去处理的,错误本身就需要付出代价. . 异常:关于异常的说明和实现可以参考http://xombat.javaeye.com/admin/show/94540,它的优点是能模拟实现c++中异常的一些优点。但是这个异常机制很脆弱,使用时要注意很多问题,而且它的性能开销肯定也会不小。 既然是用C就不要试图去模仿C++的异常处理,本省异常处理就是C++中一个极其难实现的部分,很多情况都只能依赖于操作系统去有效完整的实现. 你的这个帖子我看了,作为一种模拟方法是不错,但是既然用C还在担心函数调用开销问题,那么就简单得使用setjmp longjmp来处理吧,作为一种利用c stack特性的回滚机制还是相当好用的,可以很容易的将错误回滚到一个点上,开销也不大. . Goto语句:,当发生错误时,利用goto语句跳到相应的错误处理函数中。因为一直以来对goto语句的偏见,和goto语句本身对程序结构性的影响,所以本人一直以来没有用过这种方式,也不知道这种方式会有什么优劣。 goto的确破坏代码结构性,但是却十分有效,有不少人对goto嗤之以鼻,那么我只能对这些人嗤之以鼻了.不能因为刀会伤人就不用刀了吧. 合理使用goto会使得错误处理更加简洁明了. 我是比较推辞使用goto来集中错误处理的,这样代码会简洁不少. 总的来说,每个方式都不是尽善尽美的,不知道大家遇到这些问题是怎么处理的? 另外希望还可以讨论如下问题: . C语言中的函数调用是不是像一些人说的那样成本很高? 呼叫函数是相对成本高,主要在于处理stack数据,所以如果真的要抠到这个程度,那就尽可能减少函数参数,用指针代替结构等降低stack操作开销. 如果要说到有些cpu call消耗的时钟周期较长或则cache命中失败等问题,那么...你还能写程序吗? . 错误处理应该如何区分用户错误和应用程序错误? 当然要区分,用户错误是给用户看的,一般都是用户操作的问题,要让用户了解自己做错了什么,这样可以有效降低以后服务的成本. 而程序自身的错误则是给程序员看的,用来排除程序的bug,这些错误一般情况不应该让客户知道,因为有时候这些错误往往携带了危险数据. 所以一般可以区分error和internal两种大的错误类型,分别处理. . 如果采用错误封装的方法(方法3),错误处理需要程序结束的地方应该使用exit还是abort? 前面第3种方法有说一部分,无论哪种错误,退出后一定要释放系统无法回收的资源,虽然这个难度有点大. . 最好的方法应该是混合使用吧,(比如返回值的方法和全局errno的方法经常混合使用)该用返回值的时候用返回值,该异常的时候异常,但是什么时候该用返回,什么时候该用异常? 其实最好使用统一的处理方法,否则很不容易维护的...
一 前言: 异常处理,对于做面向对象开发的开发者来说是再熟悉不过了,例如在C#中有 try { ... } catch( Exception e){...} finally{ ..... } 在C++中,我们常常会使用 try{} ... catch(){} 块来进行异常处理。 说了那么多,那么到底什么是异常处理呢? 异常处理(又称为错误处理)功能提供了处理程序运行时出现的任何意外或异常情况的方法。 异常处理一般有两种模型,一种是"终止模型",一种是"恢复模型" "终止模型":在这种模型中,将假设错误非常关键,将以致于程序无法返回到异常发生的地方继续执行.一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行. "恢复模型":异常处理程序的工作是修正错误,然后重新尝试调动出问题的方法,并认为的二次能成功. 对于恢复模型,通常希望异常被处理之后能继续执行程序.在这种情况下,抛出异常更像是对方法的调用--可以在Java里用这种方法进行配置,以得到类似恢复的行为.(也就是说,不是抛出异常,而是调用方法修正错误.)或者,把try块放在while循环里,这样就可以不断的进入try块,直到得到满意的结果. 二 面向对象中的异常处理 大致了解了什么是异常处理后,由于异常处理在面向对象语言中使用的比较普遍,我们就先以C++为例,做一个关于异常处理的简单例子: 问题:求两个数相除的结果。 这里,隐藏这一个错误,那就是当除数为0时,会出现,所以,我们得使用异常处理来捕捉这个异常,并抛出异常信息。 具体看代码: #include <iostream> #include <exception> using namespace std; class DivideError:public exception { public: DivideError::DivideError():exception(){} const char* what(){ return "试图去除一个值为0的数字"; } }; double quotion(int numerator,int denominator) { ==denominator) //当除数为0时,抛出异常 throw DivideError(); return static_cast<double>(numerator)/denominator; } int main() { int number1; //第一个数字 int number2; //第二个数字 double result; cout<<"请输入两个数字:" ; while(cin>>number1>>number2){ try{ result=quotion(number1,number2); cout<<"结果是 :"<<result<<endl; } //end try catch(DivideError &divException){ cout<<"产生异常:" <<divException.what()<<endl; } } } 在这个例子中,我们使用了<expection>头文件中的exception类,并使DivideError类继承了它,同时重载了虚方法what(),以给出特定的异常信息。 而C#中的异常处理类则封装的更有全面,里面封装了常用的异常处理信息,这里就不多说了。 三 C语言中的异常处理 在C语言中异常处理一般有这么几种方式: .使用标准C库提供了abort()和exit()两个函数,它们可以强行终止程序的运行,其声明处于<stdlib.h>头文件中。 .使用assert(断言)宏调用,位于头文件<assert.h>中,当程序出错时,就会引发一个abort()。 .使用errno全局变量,由C运行时库函数提供,位于头文件<errno.h>中。 .使用goto语句,当出错时跳转。 .使用setjmp,longjmp进行异常处理。 接下来,我们就依次对这几种方式来看看到底是怎么做的: 我们仍旧以前面处理除数为0的异常为例子。 .使用exit()函数进行异常终止: #include <stdio.h> #include <stdlib.h> double diva(double num1,double num2) //两数相除函数 { double re; re=num1/num2; return re; } int main() { double a,b,result; printf("请输入第一个数字:"); scanf("%lf",&a); printf("请输入第二个数字:"); scanf("%lf",&b); ==b) //如果除数为0终止程序 exit(EXIT_FAILURE); result=diva(a,b); printf("相除的结果是: %.2lf\n",result); ; } 其中exit的定义如下: _CRTIMP void __cdecl __MINGW_NOTHROW exit (int) __MINGW_ATTRIB_NORETURN; exit的函数原型:void exit(int)由此,我们也可以知道EXIT_FAILURE宏应该是一个整数,exit()函数的传递参数是两个宏,一个是刚才看到的EXIT_FAILURE,还有一个是EXIT_SUCCESS从字面就可以看出一个是出错后强制终止程序,而一个是程序正常结束。他们的定义是: #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 到此,当出现异常的时候,程序是终止了,但是我们并没有捕获到异常信息,要捕获异常信息,我们可以使用注册终止函数atexit(),它的原型是这样的:intatexit(atexit_t func); 具体看如下程序: #include <stdio.h> #include <stdlib.h> void Exception(void) //注册终止函数,通过挂接到此函数,捕获异常信息 { printf("试图去除以一个为0的数字,出现异常!\n"); } int main() { double a,b,result; printf("请输入第一个数字:"); scanf("%lf",&a); printf("请输入第二个数字:"); scanf("%lf",&b); ==b) //如果除数为0终止程序 ,并挂接到模拟异常捕获的注册函数 { atexit(Exception); exit(EXIT_FAILURE); } result=diva(a,b); printf("相除的结果是: %.2lf\n",result); ; } 这里需要注意的是,atexit()函数总是被执行的,就算没有exit()函数,当程序结束时也会被执行。并且,可以挂接多个注册函数,按照堆栈结构进行执行。abort()函数与exit()函数类似,当出错时,能使得程序正常退出,这里就不多说了。 .使用assert()进行异常处理: assert()是一个调试程序时经常使用的宏,切记,它不是一个函数,在程序运行时它计算括号内的表达式,如果表达式为FALSE (), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。 另外需要注意的是:assert只有在Debug版本中才有效,如果编译为Release版本则被忽略。 我们就前面的问题,使用assert断言进行异常终止操作:构造可能出现出错的断言表达式:assert(number!=)这样,当除数为0的时候,表达式就为false,程序报告错误,并终止执行。 代码如下: 代码 #include <stdio.h> #include <assert.h> double diva(double num1,double num2) //两数相除函数 { double re; re=num1/num2; return re; } int main() { printf("请输入第一个数字:"); scanf("%lf",&a); printf("请输入第二个数字:"); scanf("%lf",&b); assert(!=b); //构造断言表达式,捕获预期异常错误 result=diva(a,b); printf("相除的结果是: %.2lf\n",result); ; } .使用errno全局变量,进行异常处理: errno全局变量主要在调式中,当系统API函数发生异常的时候,将errno变量赋予一个整数值,根据查看这个值来推测出错的原因。 其中的各个整数值都有一个相应的宏定义,表示不同的异常原因: 代码 #define EPERM 1 /* Operation not permitted */ #define ENOFILE 2 /* No such file or directory */ #define ENOENT 2 #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted function call */ #define EIO 5 /* Input/output error */ #define ENXIO 6 /* No such device or address */ #define E2BIG 7 /* Arg list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file descriptor */ #define ECHILD 10 /* No child processes */ #define EAGAIN 11 /* Resource temporarily unavailable */ #define ENOMEM 12 /* Not enough space */ #define EACCES 13 /* Permission denied */ #define EFAULT 14 /* Bad address */ /* 15 - Unknown Error */ #define EBUSY 16 /* strerror reports "Resource device" */ #define EEXIST 17 /* File exists */ #define EXDEV 18 /* Improper link (cross-device link?) */ #define ENODEV 19 /* No such device */ #define ENOTDIR 20 /* Not a directory */ #define EISDIR 21 /* Is a directory */ #define EINVAL 22 /* Invalid argument */ #define ENFILE 23 /* Too many open files in system */ #define EMFILE 24 /* Too many open files */ #define ENOTTY 25 /* Inappropriate I/O control operation */ /* 26 - Unknown Error */ #define EFBIG 27 /* File too large */ #define ENOSPC 28 /* No space left on device */ #define ESPIPE 29 /* Invalid seek (seek on a pipe?) */ #define EROFS 30 /* Read-only file system */ #define EMLINK 31 /* Too many links */ #define EPIPE 32 /* Broken pipe */ #define EDOM 33 /* Domain error (math functions) */ #define ERANGE 34 /* Result too large (possibly too small) */ /* 35 - Unknown Error */ #define EDEADLOCK 36 /* Resource deadlock avoided (non-Cyg) */ #define EDEADLK 36 /* 37 - Unknown Error */ #define ENAMETOOLONG 38 /* Filename too long (91 in Cyg?) */ #define ENOLCK 39 /* No locks available (46 in Cyg?) */ #define ENOSYS 40 /* Function not implemented (88 in Cyg?) */ #define ENOTEMPTY 41 /* Directory not empty (90 in Cyg?) */ #define EILSEQ 42 /* Illegal byte sequence */ 这里我们就不以前面的除数为0的例子来进行异常处理了,因为我不知道如何定义自己特定错误的errno,如果哪位知道,希望能给出方法。我以一个网上的例子来说明它的使用方法: 代码 #include <errno.h> #include <math.h> #include <stdio.h> int main(void) { errno = ; if (NULL == fopen("d:\\1.txt", "rb")) { printf("%d", errno); } else { printf("%d", errno); } ; } 这里试图打开一个d盘的文件,如果文件不存在,这是查看errno的值,结果是2、 当文件存在时,errno的值为初始值0。然后查看值为2的错误信息,在宏定义那边#define ENOFILE 2 /* No such file or directory */ 便知道错误的原因了。 .使用goto语句进行异常处理: goto语句相信大家都很熟悉,是一个跳转语句,我们还是以除数为0的例子,来构造一个异常处理的例子: 代码 #include <stdio.h> double diva(double num1,double num2) //两数相除函数 { double re; re=num1/num2; return re; } int main() { ; double a,b,result; ==tag) { Throw: printf("除数为0,出现异常\n"); } tag=; printf("请输入第一个数字:"); scanf("%lf",&a); printf("请输入第二个数字:"); scanf("%lf",&b); ) //捕获异常(或许这么说并不恰当,暂且这么理解) goto Throw; //抛出异常 result=diva(a,b); printf("%d\n",errno); printf("相除的结果是: %.2lf\n",result); ; } .使用setjmp和longjmp进行异常捕获与处理: setjmp和longjmp是非局部跳转,类似goto跳转作用,但是goto语句具有局限性,只能在局部进行跳转,当需要跳转到非一个函数内的地方时就需要用到setjmp和longjmp。setjmp函数用于保存程序的运行时的堆栈环境,接下来的其它地方,你可以通过调用longjmp函数来恢复先前被保存的程序堆栈环境。异常处理基本方法: 使用setjmp设置一个跳转点,然后在程序其他地方调用longjmp跳转到该点(抛出异常). 代码如下所示: #include <stdio.h> #include <setjmp.h> jmp_buf j; void Exception(void) { longjmp(j,); } double diva(double num1,double num2) //两数相除函数 { double re; re=num1/num2; return re; } int main() { double a,b,result; printf("请输入第一个数字:"); scanf("%lf",&a); printf("请输入第二个数字:"); ) { scanf("%lf",&b); ==b) Exception(); result=diva(a,b); printf("相除的结果是: %.2lf\n",result); } else printf("试图除以一个为0的数字\n"); ; }四 总结: 除了以上几种方法之外,另外还有使用信号量等等方法进行异常处理。当然在实际开发中每个人都有各种调式的技巧,而且这文章并不是说明异常处理一定要这样做,这只是对一般做法的一些总结,也不要乱使用异常处理,如果弄的不好就严重影响了程序的效率和结构,就像设计模式一样,不能胡乱使用。 作者:Skiper 出处:http://www.cnblogs.com/vimsk
错误处理 — (Error Handling) 错误代号与讯息 — (errno, strerror, perror) 与错误代号相关的讯息输出方法。 错误讯息列表 — (strerror) 用 strerror 列出所有内建的错误讯息。 档案错误 — (ferror,clearerr) 档案读取写入错误,清除错误,继续执行下去。 短程跳跃 — (goto) 函数内的跳跃,不可跨越函数。 长程跳跃 — (setjump 与 longjump) 在错误发生时,储存行程状态,执行特定程式的方法 。 讯号机制 — (signal) 拦截中断讯号的处理机制。 模拟 try ... catch — 使用跳跃机制 (setjump, longjump) 模拟 try … catch 的错误 捕捉机制。
C错误异常处理,异常处理的更多相关文章
- PHP错误以及异常处理
以前一直觉得php的异常处理没有什么,现在才发现这个还真是门学问,于是狠下心来好好研究了一下,写一篇文章,也作备忘吧. 1. php错误 无论是什么语言编程,都会有如下三种错误,当然php也不例外. ...
- Yii中的错误及异常处理
Yii中的错误及异常处理 Yii已经默认已经在CApplication上实现了异常和错误的接管,这是通过php的set_exception_handler, set_error_handler实现的. ...
- 再谈PHP错误与异常处理
博客好久没有更新了,实在惭愧,最近在忙人生大事,哈哈!这段时间没有看什么新的东西,结合项目中遇到的PHP异常处理问题,我又重新梳理了之前模糊的概念,希望对大家理解PHP异常处理有所帮助. 请一定要注意 ...
- Golang错误和异常处理的正确姿势
Golang错误和异常处理的正确姿势 错误和异常是两个不同的概念,非常容易混淆.很多程序员习惯将一切非正常情况都看做错误,而不区分错误和异常,即使程序中可能有异常抛出,也将异常及时捕获并转换成错误.从 ...
- 【PHP】解析PHP中的错误和异常处理
目录结构: contents structure [-] 错误级别 自定义处理器 设置异常日志 自定义异常类 在这篇文章中,笔者将会阐述PHP中的异常处理,希望能够对你有所帮助. 1.错误级别 PHP ...
- ThinkPHP5.0源码学习之注册错误和异常处理机制
在base.php文件中,用一句代码\think\Error::register();实现错误和异常处理机制的注册. // 注册错误和异常处理机制 \think\Error::register(); ...
- 2018/05/02 PHP 之错误与异常处理
在学习中,越学习越觉得自己基础薄弱. 在平常工作中,对于某些错误处理感觉不知道怎么下手,于是决定重新再整理一下. 强烈推荐这篇文章,真的感觉学习到了很多. 部分引用::再谈PHP错误与异常处理 -- ...
- PHP 注册错误和异常处理机制
注册错误和异常处理机制有三个PHP函数需要学习 1. register_shutdown_function('Bootstrap\Library\Frame::fatalError'); 2. set ...
- PHP常用功能块_错误和异常处理 — php(32)
一.错误和异常处理 1.1 错误类型和基本的调试方法PHP程序的错误发生一般归属于下列三个领域: 语法错误:语法错误最常见,并且也容易修复.如:代码中遗漏一个分号.这类错误会阻止脚本的执行. 运行时错 ...
- php 错误和异常处理
一.错误和异常处理 1.1 错误类型和基本的调试方法 PHP程序的错误发生一般归属于下列三个领域: 语法错误: 语法错误最常见,并且也容易修复.如:代码中遗漏一个分号.这类错误会阻止脚本的执行. 运行 ...
随机推荐
- 【LOJ】#2446. 「NOI2011」 NOI 嘉年华
题解 一道神奇的dp 我们发现关于两个东西的记录很难办,但是我们发现在固定时间区间内,如果A场地举办的活动数是一定的,那么B场地肯定举办的活动越多越好 我们预处理一个\(num[i][j]\)表示时间 ...
- HDU 1028 HDU 1398 (母函数)
题意:输入一个n 给出其所有组合数 如: 4 = 4; 4 = 3 + 1; 4 = 2 + 2; 4 = 2 + 1 + 1; 4 = 1 + 1 + 1 + 1; 重复不算 母函数入门题 ...
- JSP的学习二(请求转发与 重定向)
一: 1.介绍知识点 1). 本质区别: 请求的转发只发出了一次请求, 而重定向则发出了两次请求. 具体: ①. 请求的转发: 地址栏是初次发出请求的地址. 请求的重定向: 地址栏不再是初次发出的请 ...
- mysql 存储过程详解
MySQL 存储过程是从 MySQL 5.0 开始增加的新功能.存储过程的优点有一箩筐.不过最主要的还是执行效率和SQL 代码封装.特别是 SQL 代码封装功能,如果没有存储过程,在外部程序访问数据库 ...
- 【知了堂学习笔记】java 正则表达式
本文参考网络上面别人的博客知识产出 正则表达式基础 1.句号 假设你想要找出三个字母的单词,而且这些单词必须以“t”字母开头,以“n”字母结束.另外,假设有一本英文字典,你可以用正则表达式搜索它的全部 ...
- CodeForces528A (STLset)
题面 CodeForces 题解 横着切和竖着切是互相不影响的. 假设现在横着切成了很多段,显然此时面积最大的矩形的一边长就是这些段中长度最长的一段.竖着切的也是一样的. 所以就可以用\(set\)来 ...
- web服务端安全之分布式拒绝服务攻击
一.DDOS攻击的原理分布式拒绝服务,Distributed Denial of Service,利用目标系统网络服务功能缺陷或者直接消耗其系统资源,使得该目标系统无法提供正常的服务.通过大量合法的请 ...
- MySQL Hash索引和B-Tree索引的区别
MySQL Hash索引和B-Tree索引的区别究竟在哪里呢?相信很多人都有这样的疑问,下文对两者的区别进行了详细的分析,供您参考. MySQL Hash索引结构的特殊性,其检索效率非常高,索引的检索 ...
- 用profile协助程序性能优化
程序运行慢的原因有很多,比如存在太多的劣化代码(如在程序中存在大量的“.”操作符),但真正的原因往往是比较是一两段设计并不那么良好的不起眼的程序,比如对一序列元素进行自定义的类型转换等.因为程序性能 ...
- 【BFS】【最小生成树】Petrozavodsk Winter Training Camp 2018 Day 1: Jagiellonian U Contest, Tuesday, January 30, 2018 Problem G. We Need More Managers!
题意:给你n个点,点带权,任意两点之间的边权是它们的点权的异或值中“1”的个数,问你该图的最小生成树. 看似是个完全图,实际上有很多边是废的.类似……卡诺图的思想?从读入的点出发BFS,每次只到改变它 ...