您的位置:首页 > 运维架构 > Linux

如何在嵌入式Linux产品中做立体、覆盖产品生命期的调试 (5)

2008-01-10 23:59 525 查看
 
上接:如何在嵌入式Linux产品中做立体、覆盖产品生命期的调试 ( 4)
 
这篇谈谈error code的使用和做法:
程序不出错则大家都好,出错了,首先找谁,error code!
 
大家知道,嵌入式Linux产品的软件一般有个分层的:
从上到下依次为:
application层
middleware层/Enabler层
driver层
kernel层
 
每一层都会有error code, 下层的error code提供给上层调用时用;
所以说,上面一层的代码调用下面一层的API时,如果该API提供了error code,
则说明这个API还是较好的,如果没有,对于你纠错帮助不大。
 
下面我举几个常用的:
application调用glib的函数:
 
 
 
application调用sqlite的函数:
 
//sqlite提供error 的手段比较多
1.       直接返回错误原因
2.       返回错误码,有个函数可以根据错误码提取出错原因:
这个函数是sqlite里面比较亲切的函数:const char *sqlite_error_string (int rc);
多用这个函数,你会发现sqlite原来这么简单;
 
sqlite算是在嵌入式Linux产品中用的较广泛的数据库了,这个开源项目提供的error code/error string是继承自Glib, 并发扬广大了;
 
 
 
application调用gconf:
 
//原型
gboolean gconf_init (GError **error);
 
GError *error = NULL;
if (!gconf_init (&error))
{
fprintf (stderr, “Failed to initialize gconf, reason: %s/n”, error->message);
g_error_free (error);
error = NULL;
}
 
//在gconf系统里面,主要复制了GError的一套内容,并且把出错信息填充到GError中,
这样调用者就可以很好的获取出错信息;
 
gconf也是嵌入式Linux产品中使用的较多的用于记录setting的开源项目,对于出错的处理,继承自Glib,并没有向Sqlite那样做了扩充,应该说是中规中矩吧,也可以了。
 
 
 
上面的sqlite/gconf/dbus/gstreamre等都是使用比较多的开源软件,本省提供的error code、error string也是比较好的。
 
如果我们自己写程序,比如写一些middleware这一层的代码,就需要给上层的application提供足够好的error code的支持。
 
下面就看看如何在middleware层增加对error code的很好支持,首先研究4个开源项目的error code的做法:
A) sqlite,
B) gconf
C) gstreamer
D) dbus
 
A) sqlite的做法
    
==================sqlite 的error code 做法=============
[align=left]Sqlite的error code的做法比较简单、直白!没有什么花花肠子。[/align]
[align=left]就是error code + error string. [/align]
[align=left] [/align]
[align=left]1 定义error code(也称return code, rc)的枚举[/align]
[align=left] [/align]
[align=left]/*[/align]
[align=left]** Return values for sqlite3_exec() and sqlite3_step()[/align]
[align=left]*/[/align]
[align=left]#define SQLITE_OK           0   /* Successful result */[/align]
[align=left]/* beginning-of-error-codes */[/align]
[align=left]#define SQLITE_ERROR        1   /* SQL error or missing database */[/align]
[align=left]#define SQLITE_INTERNAL     2   /* NOT USED. Internal logic error in SQLite */[/align]
[align=left]// … 参考sqlite.h.in文件,编译后放在sqlite.h中[/align]
[align=left]#define SQLITE_DONE        101 /* sqlite3_step() has finished executing */[/align]
[align=left]/* end-of-error-codes */[/align]
 
2 定义与error code对应的字串
[align=left] [/align]
[align=left]const char *sqlite3ErrStr(int rc){[/align]
[align=left] const char *z;[/align]
[align=left] switch( rc & 0xff ){[/align]
[align=left]    case SQLITE_ROW:[/align]
[align=left]    case SQLITE_DONE:[/align]
[align=left]    case SQLITE_OK:         z = "not an error";                          break;[/align]
[align=left]    case SQLITE_ERROR:      z = "SQL logic error or missing database";   break;[/align]
[align=left]   // 参考sqlite/src/main.c中[/align]
[align=left]   [/align]
[align=left]    default:                z = "unknown error";                         break;[/align]
[align=left] }[/align]
[align=left] return z;[/align]
[align=left]}[/align]
 
[align=left] [/align]
[align=left]3 sqlite和GError的关系不大,另外sqlite还有一个很有个性的东西:[/align]
[align=left]提取“最近”发生的错误码或者错误信息![/align]
[align=left]这三个可是sqlite调试的大功臣啊!当调用sqlite的函数发生错误时,不要客气,调用这几个函数去查查错误原因,事半功倍![/align]
[align=left]const char *sqlite3_errmsg(sqlite3 *db);[/align]
[align=left]const void *sqlite3_errmsg16(sqlite3 *db);[/align]
[align=left]int sqlite3_errcode(sqlite3 *db)[/align]
 
 
 
B) gconf的做法
 
==================gconf 的error code 做法=============
Gconf的error code最没有个性,就是想方设法满足GError! 往GError中填充信息。
 
[align=left]1 定义gconf中可能出现的错误的种类,这里使用的是枚举[/align]
[align=left]/* Sync with ConfigErrorType in GConf.idl, and some switch statements in the code */[/align]
[align=left]typedef enum { /*< prefix=GCONF_ERROR >*/[/align]
[align=left] GCONF_ERROR_SUCCESS = 0,[/align]
[align=left] GCONF_ERROR_FAILED = 1,        /* Something didn't work, don't know why, probably unrecoverable[/align]
[align=left] // … 参考gconf-error.h   [/align]
[align=left] GCONF_ERROR_IN_SHUTDOWN = 16   /* server is shutting down */[/align]
[align=left]} GConfError;[/align]
 
[align=left]2 定义与上面枚举对应的错误信息字符串数组:[/align]
[align=left]static const gchar* err_msgs[] = {[/align]
[align=left] N_("Success"),[/align]
[align=left] N_("Failed"),[/align]
[align=left] // … 参考gconf-error.c[/align]
[align=left] N_("No database available to save your configuration")[/align]
[align=left]};[/align]
这点和GStreamer的差距:没有GSteamer做的巧妙
    和 DBus的差距:不能像dbus那样灵活修改;
[align=left] [/align]
[align=left]3 定义gconf的身份证,就是声明一个quark,和GStreamer类似[/align]
[align=left]#define GCONF_ERROR gconf_error_quark ()[/align]
[align=left] [/align]
[align=left]GQuark[/align]
[align=left]gconf_error_quark (void)[/align]
[align=left]{[/align]
[align=left] static GQuark err_q = 0;[/align]
[align=left] [/align]
[align=left] if (err_q == 0)[/align]
[align=left]    err_q = g_quark_from_static_string ("gconf-error-quark");[/align]
[align=left] [/align]
[align=left] return err_q;[/align]
[align=left]}[/align]
 
 
4 把错误信息填充到GError中
[align=left] [/align]
[align=left]static GError* [/align]
[align=left]gconf_error_new_valist(GConfError en, const gchar* fmt, va_list args);[/align]
[align=left] [/align]
[align=left]GError*[/align]
[align=left]gconf_error_new(GConfError en, const gchar* fmt, ...);[/align]
[align=left] [/align]
[align=left]void[/align]
[align=left]gconf_set_error      (GError** err, GConfError en, const gchar* fmt, ...);[/align]
[align=left] [/align]
[align=left]// … 具体参考gconf-error.c[/align]
从上面可以看出,GConf的error是委身于GError的,没有独立性。
 
5 外部调用GConf的接口API,大部分接口API都有一个GError** err参数,就是用这个参数接收Gconf返回的错误信息的;

 

C) gstreamer的做法
 
[align=left]==================Gstreamer 的error code 做法=============[/align]
[align=left] [/align]
[align=left]Gstreamer中如何做error code/error string的?[/align]
[align=left]在GStreamer中有4大类error:[/align]
[align=left]1 GST_CORE_ERROR[/align]
[align=left]2 GST_LIBRARY_ERROR[/align]
[align=left]3 GST_RESOURCE_ERROR[/align]
[align=left]4 GST_STREAM_ERROR[/align]
[align=left] [/align]
[align=left]每一大类都有一些细分的error:[/align]
[align=left] [/align]
[align=left]1, core类error,主要是gstreamer核心概念方面的错误[/align]
[align=left]typedef enum[/align]
[align=left]{[/align]
[align=left] GST_CORE_ERROR_FAILED = 1,[/align]
[align=left] GST_CORE_ERROR_TOO_LAZY,[/align]
[align=left] GST_CORE_ERROR_NOT_IMPLEMENTED,[/align]
[align=left] GST_CORE_ERROR_STATE_CHANGE,[/align]
[align=left] GST_CORE_ERROR_PAD,[/align]
[align=left] GST_CORE_ERROR_THREAD,[/align]
[align=left] GST_CORE_ERROR_NEGOTIATION,[/align]
[align=left] GST_CORE_ERROR_EVENT,[/align]
[align=left] GST_CORE_ERROR_SEEK,[/align]
[align=left] GST_CORE_ERROR_CAPS,[/align]
[align=left] GST_CORE_ERROR_TAG,[/align]
[align=left] GST_CORE_ERROR_MISSING_PLUGIN,[/align]
[align=left] GST_CORE_ERROR_CLOCK,[/align]
[align=left] GST_CORE_ERROR_NUM_ERRORS[/align]
[align=left]} GstCoreError;[/align]
 
[align=left]2, 库操作方面的error[/align]
[align=left]typedef enum[/align]
[align=left]{[/align]
[align=left] GST_LIBRARY_ERROR_FAILED = 1,[/align]
[align=left] GST_LIBRARY_ERROR_TOO_LAZY,[/align]
[align=left] GST_LIBRARY_ERROR_INIT,[/align]
[align=left] GST_LIBRARY_ERROR_SHUTDOWN,[/align]
[align=left] GST_LIBRARY_ERROR_SETTINGS,[/align]
[align=left] GST_LIBRARY_ERROR_ENCODE,[/align]
[align=left] GST_LIBRARY_ERROR_NUM_ERRORS[/align]
[align=left]} GstLibraryError;[/align]
 
[align=left]3,资源方面的error[/align]
[align=left] [/align]
[align=left]typedef enum[/align]
[align=left]{[/align]
[align=left] GST_RESOURCE_ERROR_FAILED = 1,[/align]
[align=left] GST_RESOURCE_ERROR_TOO_LAZY,[/align]
[align=left] GST_RESOURCE_ERROR_NOT_FOUND,[/align]
[align=left] GST_RESOURCE_ERROR_BUSY,[/align]
[align=left] GST_RESOURCE_ERROR_OPEN_READ,[/align]
[align=left] GST_RESOURCE_ERROR_OPEN_WRITE,[/align]
[align=left] GST_RESOURCE_ERROR_OPEN_READ_WRITE,[/align]
[align=left] GST_RESOURCE_ERROR_CLOSE,[/align]
[align=left] GST_RESOURCE_ERROR_READ,[/align]
[align=left] GST_RESOURCE_ERROR_WRITE,[/align]
[align=left] GST_RESOURCE_ERROR_SEEK,[/align]
[align=left] GST_RESOURCE_ERROR_SYNC,[/align]
[align=left] GST_RESOURCE_ERROR_SETTINGS,[/align]
[align=left] GST_RESOURCE_ERROR_NO_SPACE_LEFT,[/align]
[align=left] GST_RESOURCE_ERROR_NUM_ERRORS[/align]
[align=left]} GstResourceError;[/align]
 
[align=left]4 编解码方面的error[/align]
 
[align=left]typedef enum[/align]
[align=left]{[/align]
[align=left] GST_STREAM_ERROR_FAILED = 1,[/align]
[align=left] GST_STREAM_ERROR_TOO_LAZY,[/align]
[align=left] GST_STREAM_ERROR_NOT_IMPLEMENTED,[/align]
[align=left] GST_STREAM_ERROR_TYPE_NOT_FOUND,[/align]
[align=left] GST_STREAM_ERROR_WRONG_TYPE,[/align]
[align=left] GST_STREAM_ERROR_CODEC_NOT_FOUND,[/align]
[align=left] GST_STREAM_ERROR_DECODE,[/align]
[align=left] GST_STREAM_ERROR_ENCODE,[/align]
[align=left] GST_STREAM_ERROR_DEMUX,[/align]
[align=left] GST_STREAM_ERROR_MUX,[/align]
[align=left] GST_STREAM_ERROR_FORMAT,[/align]
[align=left] GST_STREAM_ERROR_NUM_ERRORS[/align]
} GstStreamError;
 
上面定义这么多的枚举量,很多人会直接去返回这个错误,没错,可以这么做。但是不直观,不能充分表达错误的原因!
[align=left]为了充分把错误的原因传达给调用者,GStreamer把上面的error枚举都做了一个对应的字符串,作的比较巧妙。[/align]
[align=left] [/align]
[align=left]做法如下:[/align]
 
1 定义一个quark宏
[align=left]#define QUARK_FUNC(string) /[/align]
[align=left]GQuark gst_ ## string ## _error_quark (void) {  /[/align]
[align=left] static GQuark quark;   /[/align]
[align=left] if (!quark)  /[/align]
[align=left]    quark = g_quark_from_static_string ("gst-" # string "-error-quark"); /[/align]
[align=left] return quark; }[/align]
 
大家知道:夸克是比原子还小的单位。在glib里面quark是用来区分唯一性的;
一般是根据一个字符串得出一个唯一的quark, 这个产出的quark就用来唯一标识那个字符串;
 
2 为每种error颁发一个身份证明:
QUARK_FUNC (core);
QUARK_FUNC (library);
QUARK_FUNC (resource);
[align=left]QUARK_FUNC (stream);[/align]
上面这4句话就是4个函数的implementation了:
 
GQuark gst_core_error_quark (void){ //…}
GQuark gst_library_error_quark (void) { //…}
GQuark gst_ resource _error_quark (void) { //…}
[align=left]GQuark gst_stream_error_quark (void) { //…}[/align]
[align=left] [/align]
[align=left]//为了方便起见,再定义二代身份证[/align]
[align=left]#define GST_LIBRARY_ERROR   gst_library_error_quark ()[/align]
[align=left]#define GST_RESOURCE_ERROR gst_resource_error_quark ()[/align]
[align=left]#define GST_CORE_ERROR      gst_core_error_quark ()[/align]
[align=left]#define GST_STREAM_ERROR    gst_stream_error_quark ()[/align]
有了表示4类error的身份证了。
 
[align=left] [/align]
[align=left]3 定义一个做字符串数组的宏[/align]
[align=left] [/align]
[align=left]#define TABLE(t, d, a, b) t[GST_ ## d ## _ERROR_ ## a] = g_strdup (b)[/align]
这里面
t 是字符串数组的名字;
d 是domain,上述枚举量的中间部分(蓝色标出);
a 是上述枚举量的后面半截(红色标出);
b 是错误字符串,这里可以给出详细的信息;
 
4 把上面定义的4类枚举变量对应的错误信息做4个字符串数组
 
4-1: core方面的详细错误信息
 
[align=left] [/align]
[align=left]static gchar **[/align]
[align=left]_gst_core_errors_init (void)[/align]
[align=left]{[/align]
[align=left] gchar **t = NULL;[/align]
[align=left] [/align]
[align=left] t = g_new0 (gchar *, GST_CORE_ERROR_NUM_ERRORS);[/align]
[align=left] [/align]
[align=left] TABLE (t, CORE, FAILED,[/align]
[align=left]      N_("GStreamer encountered a general core library error."));[/align]
[align=left] TABLE (t, CORE, TOO_LAZY,[/align]
[align=left]      N_("GStreamer developers were too lazy to assign an error code "[/align]
[align=left]          "to this error." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, NOT_IMPLEMENTED,[/align]
[align=left]      N_("Internal GStreamer error: code not implemented." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, STATE_CHANGE,[/align]
[align=left]      N_("Internal GStreamer error: state change failed." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, PAD, N_("Internal GStreamer error: pad problem." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, THREAD,[/align]
[align=left]      N_("Internal GStreamer error: thread problem." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, NEGOTIATION,[/align]
[align=left]      N_("Internal GStreamer error: negotiation problem." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, EVENT,[/align]
[align=left]      N_("Internal GStreamer error: event problem." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, SEEK,[/align]
[align=left]      N_("Internal GStreamer error: seek problem." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, CAPS,[/align]
[align=left]      N_("Internal GStreamer error: caps problem." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, TAG, N_("Internal GStreamer error: tag problem." FILE_A_BUG));[/align]
[align=left] TABLE (t, CORE, MISSING_PLUGIN,[/align]
[align=left]      N_("Your GStreamer installation is missing a plug-in."));[/align]
[align=left] TABLE (t, CORE, CLOCK,[/align]
[align=left]      N_("Internal GStreamer error: clock problem." FILE_A_BUG));[/align]
[align=left] [/align]
[align=left] return t;[/align]
[align=left]}[/align]
[align=left] [/align]
[align=left]//上面的函数的执行后的结果[/align]
[align=left]gchar **gst_core_errors = _gst_core_errors_init ();[/align]
[align=left] [/align]
[align=left]gst_core_errors [GST_CORE_ERROR_FAILED] = "GStreamer encountered a general core library error."[/align]
[align=left]gst_core_errors [GST_CORE_ERROR_TOO_LAZY] = "GStreamer developers were too lazy to assign an error code to this error."[/align]
[align=left] [/align]
[align=left]//…[/align]
[align=left] [/align]
[align=left]这样,用户就可以根据error code得出对应的error string了。[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]static gchar **[/align]
[align=left]_gst_library_errors_init (void)[/align]
[align=left]{[/align]
[align=left] // …. 省略[/align]
[align=left] return t;[/align]
[align=left]}[/align]
[align=left] [/align]
[align=left]/* initialize the dynamic table of translated resource errors */[/align]
[align=left]static gchar **[/align]
[align=left]_gst_resource_errors_init (void)[/align]
[align=left]{[/align]
[align=left] // …. 省略[/align]
[align=left]}[/align]
[align=left] [/align]
[align=left]static gchar **[/align]
[align=left]_gst_stream_errors_init (void)[/align]
[align=left]{[/align]
[align=left] // …. 省略[/align]
[align=left]}[/align]
 
具体可以参考gsterror.h/.c
 
这样就有了4个字符串数组。怎么来区分呢,就是用quark和error code:
 
[align=left]gchar *[/align]
[align=left]gst_error_get_message (GQuark domain, gint code)[/align]
[align=left]{[/align]
[align=left] static gchar **gst_core_errors = NULL;[/align]
[align=left] static gchar **gst_library_errors = NULL;[/align]
[align=left] static gchar **gst_resource_errors = NULL;[/align]
[align=left] static gchar **gst_stream_errors = NULL;[/align]
[align=left] [/align]
[align=left] gchar *message = NULL;[/align]
[align=left] [/align]
[align=left] /* initialize error message tables if necessary */[/align]
[align=left] if (gst_core_errors == NULL)[/align]
[align=left]    gst_core_errors = _gst_core_errors_init ();[/align]
[align=left] if (gst_library_errors == NULL)[/align]
[align=left]    gst_library_errors = _gst_library_errors_init ();[/align]
[align=left] if (gst_resource_errors == NULL)[/align]
[align=left]    gst_resource_errors = _gst_resource_errors_init ();[/align]
[align=left] if (gst_stream_errors == NULL)[/align]
[align=left]    gst_stream_errors = _gst_stream_errors_init ();[/align]
[align=left] [/align]
[align=left] // 根据身份证和error code , 提取error string.[/align]
[align=left] if (domain == GST_CORE_ERROR)[/align]
[align=left]    message = gst_core_errors[code];[/align]
[align=left] else if (domain == GST_LIBRARY_ERROR)[/align]
[align=left]    message = gst_library_errors[code];[/align]
[align=left] else if (domain == GST_RESOURCE_ERROR)[/align]
[align=left]    message = gst_resource_errors[code];[/align]
[align=left] else if (domain == GST_STREAM_ERROR)[/align]
[align=left]    message = gst_stream_errors[code];[/align]
[align=left] else {[/align]
[align=left]    g_warning ("No error messages for domain %s", g_quark_to_string (domain));[/align]
[align=left]    return g_strdup_printf (_("No error message for domain %s."),[/align]
[align=left]        g_quark_to_string (domain));[/align]
[align=left] }[/align]
[align=left] if (message)[/align]
[align=left]    return g_strdup (_(message));[/align]
[align=left] else[/align]
[align=left]    return[/align]
[align=left]        g_strdup_printf (_[/align]
[align=left]        ("No standard error message for domain %s and code %d."),[/align]
[align=left]        g_quark_to_string (domain), code);[/align]
[align=left]}[/align]
 
 
如果开发middleware的话,GStreamer的error code的做法就非常值得参考;如果做application可以直接return error code, 或者也这么做,好像application很少有人这么干过。
 
 

D) dbus的做法
 
==================dbus 的error code 做法=============
 
Dbus的error code的做法有另外一种风格,可以接收可变参数。
 
1 定义一个数据结构DBusError
[align=left] [/align]
[align=left]typedef struct DBusError DBusError;[/align]
[align=left] [/align]
[align=left]/**[/align]
[align=left] * Object representing an exception.[/align]
[align=left] */[/align]
[align=left]struct DBusError[/align]
[align=left]{[/align]
[align=left] const char *name;    /**< error name */ // 主要的[/align]
[align=left] const char *message; /**< error message */ // 主要的[/align]
[align=left] [/align]
[align=left] unsigned int dummy1 : 1; /**< placeholder */[/align]
[align=left] unsigned int dummy2 : 1; /**< placeholder */[/align]
[align=left] unsigned int dummy3 : 1; /**< placeholder */[/align]
[align=left] unsigned int dummy4 : 1; /**< placeholder */[/align]
[align=left] unsigned int dummy5 : 1; /**< placeholder */[/align]
[align=left] [/align]
[align=left] void *padding1; /**< placeholder */[/align]
[align=left]};[/align]
 
2 然后dbus提供几个函数对这个数据结构进行分配内存、赋值、释放等的操作;
[align=left] [/align]
[align=left]// 分配内存[/align]
[align=left]void       dbus_error_init      (DBusError       *error);[/align]
[align=left] [/align]
[align=left]// 释放[/align]
[align=left]void        dbus_error_free      (DBusError       *error);[/align]
[align=left] [/align]
[align=left]// 这是dbus的特色菜肴,能灵活的对DBusError填充想填充的内容,不必事先定死[/align]
[align=left]void        dbus_set_error       (DBusError       *error,[/align]
[align=left]                                  const char      *name,[/align]
[align=left]                                  const char      *message,[/align]
[align=left]                                  ...);[/align]
[align=left]// 这个是上面那个函数的简化版本[/align]
[align=left]void        dbus_set_error_const (DBusError       *error,[/align]
[align=left]                                  const char      *name,[/align]
[align=left]                                  const char      *message);[/align]
[align=left] [/align]
[align=left]void        dbus_move_error      (DBusError       *src,[/align]
[align=left]                                  DBusError       *dest);[/align]
[align=left]// 查询之用[/align]
[align=left]dbus_bool_t dbus_error_has_name (const DBusError *error,[/align]
[align=left]                                  const char      *name);[/align]
[align=left]dbus_bool_t dbus_error_is_set    (const DBusError *error);[/align]
 
具体实现,大家可以参考dbus-error.c
 
如何使用上面的Error呢?分为外部和内部使用
1先看dbus内部如何使用的:
1-1 定义一些常见的error string, 这是准备填充到DBusError name字段上去的;
[align=left] [/align]
[align=left]#define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed"[/align]
[align=left]#define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory"[/align]
[align=left]//……., 参考dbus-protocol.h[/align]
[align=left]#define DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"[/align]
 
1-2 初始化一个DBusError,并且填充错误信息给它
[align=left] [/align]
[align=left]DBusError error;[/align]
[align=left]dbus_error_init (&error);[/align]
[align=left] [/align]
[align=left]比如说[/align]
[align=left]dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);[/align]
[align=left] [/align]
[align=left]或者://这个就是往DBusError的message字段填充可变参数,这样信息可以灵活点[/align]
[align=left]        dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,[/align]
[align=left]                        "Process %s received signal %d",[/align]
[align=left]                        sitter->executable, WTERMSIG (sitter->status));[/align]
 
2 外部如果调用dbus的API,并且该API有个参数DBusError *error的话,可以这样调用
[align=left] [/align]
[align=left]//同样也是初始化一个error[/align]
[align=left]DBusError error;[/align]
[align=left]dbus_error_init (&error);[/align]
[align=left] [/align]
[align=left]//然后调用dbus API[/align]
[align=left]If (!dbus_message_get_args (msg, &error, …)[/align]
[align=left]{[/align]
[align=left]    printf (“Can’t get arguments: %s”, error.message);[/align]
[align=left]    dbus_error_free (&error); //别忘记释放[/align]
[align=left]}[/align]
 
大家可以看到,外部调用非常简单,其实我在这里聊dbus的error code,主要是想借鉴dbus内部调用的方式,以及DBusError的实现方式;
我们知道,dbus一般是作为middleware一层的代表,这种灵活多变的error code的做法也是继承自Glib的。在middleware一层,可以多考虑这种做法,比较专业,能传递更多的信息。

总结:

 
比较而言:
1 GconfError就是GError的升级版本;
2 GStreamer的Error分类思想很好,特别对于提供复杂功能的middleware,可以借鉴;
3 DBusError的可变填充比较好;
4 Sqlite 完全就是个一对一的关系,比较有特色的就是可以提取“最新”的错误,很有用;

 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息