概述
在C/C++程序中,设定了三种处理程序错误/异常的方法,来表达程序出错了,它们在OpenCV库中也有体现。
- 利用函数返回值/某些全局变量。
- 利用断言。
- 利用异常(try-throw-catch)。
以下代码在OpenCV 2.4.4和g++ 4.6.3编译通过。
C/C++
主要参照C++参考中对各标准库的文字解释和示例代码,完成下述内容。
errno
“errno.h”/“cerrno”头文件中定义了int类型的全局变量errno,初始值是0,所有C/C++标准库函数都有可能将值修改为非0,表示程序出错了。errno会被重复修改,值是最后一次修改的结果,也就表达了最后一次错误的内容。
errno不仅会被标准库函数修改,也能被用户程序修改。一般用来检查标准库函数是否出错,建议的使用方法是:在使用之前先置0,然后调用库函数,接着检查该值。
一般来说,不仅需要检测到错误,还需要将错误提示出来。这就需要用到另外两个标准库函数。
- “stdio.h”/“cstdio”中的“perror()”函数
对errno的调用是隐藏起来的,所以不用显式声明库的头文件。
1 #include <cstdio>
2
3 int main(int argc, char **argv) {
4 FILE *pFile = fopen("unexist.txt", "rb");
5 if (NULL == pFile) {
6 perror("Error");
7 } else {
8 fclose(pFile);
9 }
10 return 0;
11 }
运行结果:
1 Error: No such file or directory
其中,“: No such file or directory”是函数“perror()”添加的。
- “string.h”/“cstring”中的“strerror()”函数
对errno的调用是显式的,所以需要声明库的头文件。
1 #include <cerrno>
2 #include <cstring>
3 #include <cstdio>
4 #include <iostream>
5
6 int main(int argc, char **argv) {
7 FILE *pFile = fopen("unexist.txt", "rb");
8 if (NULL == pFile) {
9 std::cout << "Error: " << strerror(errno) << std::endl;
10 } else {
11 fclose(pFile);
12 }
13 return 0;
14 }
运行结果:
1 Error: No such file or directory
其中,“No such file or directory”是函数“strerror()”输出的。
assert
“assert.h”/“cassert”头文件中定义了宏函数 void assert(int expression) 如果表达式“expression”的值为0,则触发错误,在标准错误设备(stderr)上输出一条消息,并立刻调用“abort()”函数,退出程序。
输出内容依赖于库的实现,但一般会包含表达式、源文件名称、行号。
设计该宏函数是为了捕捉编程错误,而不是用户输入错误或者程序运行时错误。当程序依照Release模式编译时,通常需要提前先定义“NDEBUG”宏,则代码中的assert语句将不起作用。
1 //#define NDEBUG
2 #include <cassert>
3 #include <iostream>
4
5 int main(int argc, char **argv) {
6 const size_t a = 10;
7 assert(a == 100);
8 return 0;
9 }
运行结果:
1 test: test.cpp:7: int main(int, char**): Assertion `a == 100' failed.
signal
“signal.h”/“csignal”头文件,设计主要用来捕捉程序运行中的信号,包括(担心翻译出来不准确,就直接拷贝过来了):
- SIGABRT (Signal Abort) Abnormal termination, such as is initiated by the abort function.
- SIGFPE (Signal Floating-Point Exception) Erroneous arithmetic operation, such as zero divide or an operation resulting in overflow (not necessarily with a floating-point operation).
- SIGILL (Signal Illegal Instruction) Invalid function image, such as an illegal instruction. This is generally due to a corruption in the code or to an attempt to execute data.
- SIGINT (Signal Interrupt) Interactive attention signal. Generally generated by the application user.
- SIGSEGV (Signal Segmentation Violation) Invalid access to storage: When a program tries to read or write outside the memory it has allocated.
- SIGTERM (Signal Terminate) Termination request sent to program.
大概流程是:利用“raise()”函数触发信号,或者程序运行中某种事件触发信号,程序立即进入通过“signal()”函数注册的对应的处理函数,然后程序回来继续运行。
这方面网上详细资料很多,就不多解释了。下面例子是利用SIGINT信号修改signaled值。这里利用了“raise()”函数。
1 #include <csignal>
2 #include <iostream>
3
4 sig_atomic_t signaled = 0;
5
6 void my_handler(int param) {
7 std::cout << "In my_handler() function" << std::endl;
8 signaled = 1;
9 }
10
11 int main(int argc, char **argv) {
12 void (*handler)(int);
13 handler = signal(SIGINT, my_handler);
14 std::cout << "Wait for SIGINT." << std::endl;
15 raise(SIGINT);
16 std::cout << "Continue. Exit." << std::endl;
17 return 0;
18 }
特别指出,在my_handler()中调用标准输入输出函数是不建议的,不应该的,不合适的,应当避免,这里仅仅为了让执行顺序更清晰。请一定注意!
运行结果:
1 Wait for SIGINT.
2 In my_handler() function
3 Continue. Exit.
利用键盘触发:
1 #include <csignal>
2 #include <iostream>
3
4 sig_atomic_t signaled = 0;
5
6 void my_handler(int param) {
7 std::cout << "In my_handler() function" << std::endl;
8 signaled = 1;
9 }
10
11 int main(int argc, char **argv) {
12 void (*handler)(int);
13 handler = signal(SIGINT, my_handler);
14 std::cout << "Wait for SIGINT." << std::endl;
15 while (!signaled);
16 std::cout << "Continue. Exit." << std::endl;
17 return 0;
18 }
运行结果:
1 Wait for SIGINT.
2 ^CIn my_handler() function <---这里按下了ctrl-c组合键。
3 Continue. Exit.
exception
“exception”头文件定义了基本的异常类和几个异常处理函数。“stdexcept”头文件定义了两个派生类,分别是逻辑错误和运行时错误。“fenv.h”/“cfenv”头文件定义了跟浮点数有关的异常,但该头文件是新的C++标准才有的(C++ 11),所以暂时不讨论。
异常的继承关系(不包括C++ 11的内容):
exception |-- bad_alloc |-- bad_cast |-- bad_exception |-- bad_typeid |-- ios_base::failure |-- logic_error | |-- domain_error | |-- invalid_error | |-- length_error | |-- out_of_range |-- runtime_error |-- range_error |-- overflow_error |-- underflow_error
这方面网上详细资料很多,就不多解释了。
OpenCV
主要参照OpenCV参考手册中的文字解释和示例代码,使用C++语法,完成下述内容。
CV_Assert
CV_Assert与前面的assert基本一致。当条件为0的时候,自动触发(raise)一个错误(下面要讲的error)。该表达式在Debug和Release两种编译模式下都有效。另一个CV_DbgAssert仅在Debug编译模式有效。
1 #include <opencv2/opencv.hpp>
2
3 int main(int argc, char **argv) {
4 CV_DbgAssert(3 == 2);
5 CV_Assert(1 == 0);
6 return 0;
7 }
Debug模式编译,运行结果:
1 OpenCV Error: Assertion failed (3 == 2) in main, file test.cpp, line 4
2 terminate called after throwing an instance of 'cv::Exception'
3 what(): test.cpp:197: error: (-215) 3 == 2 in function main
Release模式编译,运行结果:
1 OpenCV Error: Assertion failed (1 == 0) in main, file test.cpp, line 5
2 terminate called after throwing an instance of 'cv::Exception'
3 what(): test.cpp:198: error: (-215) 1 == 0 in function main
error
具体有三种调用方式。
- 第一种
函数“error()”,参数是一个cv::Exception对象。
1 #include <opencv2/opencv.hpp>
2
3 int main(int argc, char **argv) {
4 error(cv::Exception(10, "Error description", "main", "test.cpp", 4));
5 return 0;
6 }
运行结果:
1 OpenCV Error: Unknown status code 10 (Error description) in main, file test.cpp, line 4
2 terminate called after throwing an instance of 'cv::Exception'
3 what(): test.cpp:4: error: (10) Error description in function main
- 第二种
函数“CV_Error(error_code, error_msg)”,参数是错误代码和错误描述。
1 #include <opencv2/opencv.hpp>
2
3 int main(int argc, char **argv) {
4 CV_Error(10, "Error description.");
5 return 0;
6 }
运行结果:
1 OpenCV Error: Unknown status code 10 (Error description.) in main, file test.cpp, line 4
2 terminate called after throwing an instance of 'cv::Exception'
3 what(): test.cpp:4: error: (10) Error description. in function main
- 第三种
函数“CV_Error_(error_code, (args))”,参数是错误代码和错误描述,但错误描述支持动态生成。
1 #include <opencv2/opencv.hpp>
2
3 int main(int argc, char **argv) {
4 size_t a = 0;
5 size_t b = 255;
6 CV_Error_(10, ("value a = %d, b = %d", a, b));
7 return 0;
8 }
运行结果:
1 OpenCV Error: Unknown status code 10 (value a = 0, b = 255) in main, file test.cpp, line 6
2 terminate called after throwing an instance of 'cv::Exception'
3 what(): test.cpp:6: error: (10) value a = 0, b = 255 in function main
- 关于error_code
OpenCV内定了如下错误代码,都是int类型。
1 typedef int CVStatus;
2
3 enum {
4 CV_StsOk= 0, /* everithing is ok */
5 CV_StsBackTrace= -1, /* pseudo error for back trace */
6 CV_StsError= -2, /* unknown /unspecified error */
7 CV_StsInternal= -3, /* internal error (bad state) */
8 CV_StsNoMem= -4, /* insufficient memory */
9 CV_StsBadArg= -5, /* function arg/param is bad */
10 CV_StsBadFunc= -6, /* unsupported function */
11 CV_StsNoConv= -7, /* iter. didn't converge */
12 CV_StsAutoTrace= -8, /* tracing */
13 CV_HeaderIsNull= -9, /* image header is NULL */
14 CV_BadImageSize= -10, /* image size is invalid */
15 CV_BadOffset= -11, /* offset is invalid */
16 CV_BadDataPtr= -12, /**/
17 CV_BadStep= -13, /**/
18 CV_BadModelOrChSeq= -14, /**/
19 CV_BadNumChannels= -15, /**/
20 CV_BadNumChannel1U= -16, /**/
21 CV_BadDepth= -17, /**/
22 CV_BadAlphaChannel= -18, /**/
23 CV_BadOrder= -19, /**/
24 CV_BadOrigin= -20, /**/
25 CV_BadAlign= -21, /**/
26 CV_BadCallBack= -22, /**/
27 CV_BadTileSize= -23, /**/
28 CV_BadCOI= -24, /**/
29 CV_BadROISize= -25, /**/
30 CV_MaskIsTiled= -26, /**/
31 CV_StsNullPtr= -27, /* null pointer */
32 CV_StsVecLengthErr= -28, /* incorrect vector length */
33 CV_StsFilterStructContentErr= -29, /* incorr. filter structure content */
34 CV_StsKernelStructContentErr= -30, /* incorr. transform kernel content */
35 CV_StsFilterOffsetErr= -31, /* incorrect filter ofset value */
36 CV_StsBadSize= -201, /* the input/output structure size is incorrect */
37 CV_StsDivByZero= -202, /* division by zero */
38 CV_StsInplaceNotSupported= -203, /* in-place operation is not supported */
39 CV_StsObjectNotFound= -204, /* request can't be completed */
40 CV_StsUnmatchedFormats= -205, /* formats of input/output arrays differ */
41 CV_StsBadFlag= -206, /* flag is wrong or not supported */
42 CV_StsBadPoint= -207, /* bad CvPoint */
43 CV_StsBadMask= -208, /* bad format of mask (neither 8uC1 nor 8sC1)*/
44 CV_StsUnmatchedSizes= -209, /* sizes of input/output structures do not match */
45 CV_StsUnsupportedFormat= -210, /* the data format/type is not supported by the function*/
46 CV_StsOutOfRange= -211, /* some of parameters are out of range */
47 CV_StsParseError= -212, /* invalid syntax/structure of the parsed file */
48 CV_StsNotImplemented= -213, /* the requested function/feature is not implemented */
49 CV_StsBadMemBlock= -214, /* an allocated block has been corrupted */
50 CV_StsAssert= -215, /* assertion failed */
51 CV_GpuNotSupported= -216,
52 CV_GpuApiCallError= -217,
53 CV_OpenGlNotSupported= -218,
54 CV_OpenGlApiCallError= -219
55 };
Exception
OpenCV中定义的标准异常类型。构造函数主要会用到如下形式:
1 Exception(int _code, const string& _err, const string& _func, const string& _file, int _line);
可以用做函数“error()”的参数,也可以在try中作为throw的对象,然后被catch。
1 #include <opencv2/opencv.hpp>
2
3 int main(int argc, char **argv) {
4 try {
5 throw cv::Exception(10, "Error description.", "main", "test.cpp", 5);
6 } catch (cv::Exception &ex) {
7 std::cout << ex.what() << std::endl;
8 }
9 return 0;
10 }
运行结果:
1 test.cpp:5: error: (10) Error description. in function main