概述
一、背景
以前大量使用c语言进行嵌入式软件开发的时候,对于错误类型比较常见的方式大概有:
- 使用define的宏定义
- 使用enum的枚举
比如这里需要定义四个错误类型,成功,失败,严重错误,未定义错误。
如果使用宏定义的方式来定义,形如:
#define ERR_OK 0
#define ERR_FAIL 1
#define ERR_FATAL 2
#define ERR_UNDEFINED 3
如果使用枚举的方式来定义,形如:
typedef enum _eError
{
ERR_Ok = 0,
ERR_Fail,
ERR_Fatal,
ERR_Undefined,
}ErrorType;
从形式上来看,它们都非常的简洁轻量,但是在进行Debug的时候,如果输出的log中只是这些数值错误号的话,就非常的麻烦,还必须得时刻与定义的错误类型进行对比已确认到底是什么错误。
所以如果在输出log时,就能直接输出错误信息的字符串,那就会方便很多了。比如c语言当中的 errno就是错误号(数值),可以通过strerror(errno)的方式获取某错误号对应的错误信息的字符串。
当然如果我们自定义的错误类型也要实现这样的功能,那么除了以上的错误类型定义之外,还必须专门定制实现一些函数接口来让我们获取错误信息的字符串。
有时候,如果我们开发的软件是一个library的方式发布,很有可能我们会用到不同类别的错误类型,比如
- 用于library接口的API的外部错误类型,供library的用户使用
- 用于library内部的错误类型,供library的开发人员使用
这时,有可能需要开发两个获取错误信息的接口,也是比较麻烦的。
二、c++解决方案
如果你是像c一样使用c++的话,那这部分你就不需要看了,自行忽略吧,当我没写。
虽然c++被很多人说这样不好,那样不足,但不可否认,它还是有些好东西的。比如封装,重载等等。
这里我们需要做的就是使用c++的封装,重载等特性来实现错误类型的定义,并能方便的获取错误信息。
- 首先定义错误类型的结构体:
struct ErrorType
{
int code = 0; /** error code( or number) */
const char* desc = ""; /** the describe of error, aways not null */
};
你可能要说,你这里不也是像c一样使用字符串指针吗? 这里之所以要这样用,是为了节省空间,一个string对象的size有二三十个字节,略大了一点。
- 其次是重载操作运算符,因为错误类型定义出来,其目的就是拿来使用的,赋值,对比等都是常用的操作
/** error type */
struct ErrorType
{
int code = 0; /** error code( or number) */
const char* desc = ""; /** the describe of error, aways not null */
ErrorType(int cd, const char* dsc)
:code(cd), desc(dsc)
{
}
inline bool operator==(const ErrorType& et) const
{
return (code == et.code);
}
inline bool operator!=(const ErrorType& et) const
{
return (code != et.code);
}
inline ErrorType& operator=(const ErrorType& et)
{
code = et.code;
desc = et.desc;
return *this;
}
};
这里的对比包括了,相等和不相等两种,就以上实现绝大多数情况下就已经够用了。
2.1 用c++实现错误类型定义
还是以第一章为例,定义四种错误类型。 这里和第一章有一点不一样的是,声明是在头文件中进行的,但具体的定义是在cpp源文件中实现的。
先来看头文件(假设为:errorType.h)
/************************************************************************/
/** 这部分是为了兼容visual studio和gcc对于动态库类型导出修饰符 */
/** macro define for special tool chain. */
#if defined(__GNUC__) /** !!!for gcc */
#define G_GCC_VERSION(maj,min)
((__GNUC__ > (maj)) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min)))
/** define API export macro */
#if G_GCC_VERSION(4,0) //for gcc(version >= 4.0)
#define G_DLL_EXPORT __attribute__((visibility("default")))
#else
#define G_DLL_EXPORT
#endif
#elif defined(_MSC_VER) /** !!!for visual studio */
/** auto define API export macro */
#if !defined(DLL_EXPORT) && defined(_WINDLL) //todo,process _USRDLL,_AFXDLL
#define DLL_EXPORT
#endif
#if defined (DLL_EXPORT)
#define G_DLL_EXPORT __declspec(dllexport)
#else
#define G_DLL_EXPORT __declspec(dllimport)
#endif
#else /** !!!for unknown tool chain */
///
#error "!!unspport this toolchain at now!!"
#endif /** !!! end of tool chain define */
/** general global variable decorate macro(for external reference ) */
#define G_VAR extern G_DLL_EXPORT
/** general const global variable decorate macro(for external reference ) */
#define G_CVAR G_VAR const
/************************************************************************/
G_CVAR ErrorType ERR_OK;
G_CVAR ErrorType ERR_FAIL;
G_CVAR ErrorType ERR_FATAL;
G_CVAR ErrorType ERR_UNDEFINED;
源文件的具体实现(假设为:ErrorType.cpp):
G_CVAR ErrorType ERR_OK = { 0, "Success" };
G_CVAR ErrorType ERR_FAIL = { 1, "Fail" };
G_CVAR ErrorType ERR_FATAL = { 2, "Fatal" };
G_CVAR ErrorType ERR_UNDEFINED = { 3, "undefined" };
2.2 使用方式
这里用c++方式实现的错误类型定义和c语言的实现在使用方式上是差不多的。形如:
#include "ErrorType.h"
ErrorType func1()
{
/** todo something */
return ERR_OK;
}
ErrorType func2()
{
ErrorType ret = ERR_OK;
ret = func1();
if (ret != ERR_OK)
{
/**这里就可以直接使用错误类型的 ‘desc’ 成员变量来获得错误信息的字符串,相当方便 */
LOG("do func1 failed(%d, %s)n", ret.code, ret.desc);
}
return ret;
}
最后
以上就是优美鸡翅为你收集整理的以c++的方式实现error类型的定义的全部内容,希望文章能够帮你解决以c++的方式实现error类型的定义所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复