📄 error_reporting.sgml
字号:
<refentry id="glib-Error-Reporting"><refmeta><refentrytitle>Error Reporting</refentrytitle><manvolnum>3</manvolnum><refmiscinfo>GLIB Library</refmiscinfo></refmeta><refnamediv><refname>Error Reporting</refname><refpurpose>a system for reporting errors.</refpurpose></refnamediv><refsynopsisdiv><title>Synopsis</title><synopsis>#include <glib.h>struct <link linkend="GError">GError</link>;<link linkend="GError">GError</link>* <link linkend="g-error-new">g_error_new</link> (<link linkend="GQuark">GQuark</link> domain, <link linkend="gint">gint</link> code, const <link linkend="gchar">gchar</link> *format, ...);<link linkend="GError">GError</link>* <link linkend="g-error-new-literal">g_error_new_literal</link> (<link linkend="GQuark">GQuark</link> domain, <link linkend="gint">gint</link> code, const <link linkend="gchar">gchar</link> *message);void <link linkend="g-error-free">g_error_free</link> (<link linkend="GError">GError</link> *error);<link linkend="GError">GError</link>* <link linkend="g-error-copy">g_error_copy</link> (const <link linkend="GError">GError</link> *error);<link linkend="gboolean">gboolean</link> <link linkend="g-error-matches">g_error_matches</link> (const <link linkend="GError">GError</link> *error, <link linkend="GQuark">GQuark</link> domain, <link linkend="gint">gint</link> code);void <link linkend="g-set-error">g_set_error</link> (<link linkend="GError">GError</link> **err, <link linkend="GQuark">GQuark</link> domain, <link linkend="gint">gint</link> code, const <link linkend="gchar">gchar</link> *format, ...);void <link linkend="g-propagate-error">g_propagate_error</link> (<link linkend="GError">GError</link> **dest, <link linkend="GError">GError</link> *src);void <link linkend="g-clear-error">g_clear_error</link> (<link linkend="GError">GError</link> **err);</synopsis></refsynopsisdiv><refsect1><title>Description</title><para>GLib provides a standard method of reporting errors from a called function tothe calling code. (This is the same problem solved by exceptions in otherlanguages.) It's important to understand that this method is both a<emphasis>data type</emphasis> (the <link linkend="GError">GError</link> object) and a <emphasis>set ofrules.</emphasis> If you use <link linkend="GError">GError</link> incorrectly, then your code will notproperly interoperate with other code that uses <link linkend="GError">GError</link>, and users of your APIwill probably get confused.</para><para>First and foremost: <emphasis><link linkend="GError">GError</link> should only be used to reportrecoverable runtime errors, never to report programming errors.</emphasis> Ifthe programmer has screwed up, then you should use <link linkend="g-warning">g_warning</link>(),<link linkend="g-return-if-fail">g_return_if_fail</link>(), <link linkend="g-assert">g_assert</link>(), <link linkend="g-error">g_error</link>(), or some similar facility.(Incidentally, remember that the <link linkend="g-error">g_error</link>() function should<emphasis>only</emphasis> be used for programming errors, it should not be usedto print any error reportable via <link linkend="GError">GError</link>.)</para><para>Examples of recoverable runtime errors are "file not found" or "failed to parseinput." Examples of programming errors are "NULL passed to <link linkend="strcmp">strcmp</link>()" or"attempted to free the same pointer twice." These two kinds of errors arefundamentally different: runtime errors should be handled or reported to theuser, programming errors should be eliminated by fixing the bug in the program.This is why most functions in GLib and GTK+ do not use the <link linkend="GError">GError</link> facility.</para><para>Functions that can fail take a return location for a <link linkend="GError">GError</link> as their last argument. For example:<informalexample><programlisting>gchar* g_file_get_contents (const gchar *filename, GError **error);</programlisting></informalexample>If you pass a non-<literal>NULL</literal> value for the <literal>error</literal> argument, it should point to a location where an error can be placed. For example:<informalexample><programlisting>gchar *contents;GError *err = NULL;contents = g_file_get_contents ("foo.txt", &err);g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));if (err != NULL) { /* Report error to user, and free error */ g_assert (contents == NULL); fprintf (stderr, "Unable to read file: <literal>s</literal>\n", err->message); g_error_free (err); } else { /* Use file contents */ g_assert (contents != NULL); }</programlisting></informalexample>Note that <literal>err != NULL</literal> in this example is a<emphasis>reliable</emphasis> indicator of whether<link linkend="g-file-get-contents">g_file_get_contents</link>() failed. Also, <link linkend="g-file-get-contents">g_file_get_contents</link>() uses theconvention that a <literal>NULL</literal> return value means an error occurred (but notall functions use this convention).</para><para>Because <link linkend="g-file-get-contents">g_file_get_contents</link>() returns <literal>NULL</literal> on failure, if you are onlyinterested in whether it failed and don't need to display an error message, youcan pass <literal>NULL</literal> for the <literal>error</literal> argument:<informalexample><programlisting>contents = g_file_get_contents ("foo.txt", NULL); /* ignore errors */if (contents != NULL) /* no error occurred */ ;else /* error */ ;</programlisting></informalexample></para><para>The <link linkend="GError">GError</link> object contains three fields: <literal>domain</literal> indicatesthe module the error-reporting function is located in, <literal>code</literal>indicates the specific error that occurred, and <literal>message</literal> is auser-readable error message with as many details as possible. Several functionsare provided to deal with an error received from a called function:<link linkend="g-error-matches">g_error_matches</link>() returns <literal>TRUE</literal> if the error matches a given domain and code,<link linkend="g-propagate-error">g_propagate_error</link>() copies an error into an error location (so the callingfunction will receive it), and <link linkend="g-clear-error">g_clear_error</link>() clears an error location byfreeing the error and resetting the location to <literal>NULL</literal>. To display an error to theuser, simply display <literal>error->message</literal>, perhaps along withadditional context known only to the calling function (the file being opened, orwhatever -- though in the <link linkend="g-file-get-contents">g_file_get_contents</link>() case,<literal>error->message</literal> already contains a filename).</para><para>When implementing a function that can report errors, the basic tool is<link linkend="g-set-error">g_set_error</link>(). Typically, if a fatal error occurs you want to <link linkend="g-set-error">g_set_error</link>(),then return immediately. <link linkend="g-set-error">g_set_error</link>() does nothing if the error location passedto it is <literal>NULL</literal>. Here's an example:<informalexample><programlisting>gintfoo_open_file (GError **error){ gint fd; fd = open ("file.txt", O_RDONLY); if (fd < 0) { g_set_error (error, FOO_ERROR, /* error domain */ FOO_ERROR_BLAH, /* error code */ "Failed to open file: <literal>s</literal>", /* error message format string */ g_strerror (errno)); return -1; } else return fd;}</programlisting></informalexample></para><para>Things are somewhat more complicated if you yourself call another function thatcan report a <link linkend="GError">GError</link>. If the sub-function indicates fatal errors in some wayother than reporting a <link linkend="GError">GError</link>, such as by returning <literal>TRUE</literal> on success, you cansimply do the following:<informalexample><programlisting>gbooleanmy_function_that_can_fail (GError **err){ g_return_val_if_fail (err == NULL || *err == NULL, FALSE); if (!sub_function_that_can_fail (err)) { /* assert that error was set by the sub-function */ g_assert (err == NULL || *err != NULL); return FALSE; } /* otherwise continue, no error occurred */ g_assert (err == NULL || *err == NULL);}</programlisting></informalexample></para><para>If the sub-function does not indicate errors other than by reporting a <link linkend="GError">GError</link>, you need to create a temporary <link linkend="GError">GError</link> since the passed-in one may be <literal>NULL</literal>.<link linkend="g-propagate-error">g_propagate_error</link>() is intended for use in this case.<informalexample><programlisting>gbooleanmy_function_that_can_fail (GError **err){ GError *tmp_error; g_return_val_if_fail (err == NULL || *err == NULL, FALSE); tmp_error = NULL; sub_function_that_can_fail (&tmp_error); if (tmp_error != NULL) { /* store tmp_error in err, if err != NULL, * otherwise call g_error_free(<!>) on tmp_error */ g_propagate_error (err, tmp_error); return FALSE; } /* otherwise continue, no error occurred */}</programlisting></informalexample></para><para>Error pileups are always a bug. For example, this code is incorrect:<informalexample><programlisting>gbooleanmy_function_that_can_fail (GError **err){ GError *tmp_error; g_return_val_if_fail (err == NULL || *err == NULL, FALSE); tmp_error = NULL; sub_function_that_can_fail (&tmp_error); other_function_that_can_fail (&tmp_error); if (tmp_error != NULL) { g_propagate_error (err, tmp_error); return FALSE; }}</programlisting></informalexample><literal>tmp_error</literal> should be checked immediately after<function><link linkend="sub-function-that-can-fail">sub_function_that_can_fail</link>()</function>, and either cleared or propagated upward. The ruleis: <emphasis>after each error, you must either handle the error, or return it to thecalling function</emphasis>. Note that passing <literal>NULL</literal> for the error location is theequivalent of handling an error by always doing nothing about it. So thefollowing code is fine, assuming errors in <function><link linkend="sub-function-that-can-fail">sub_function_that_can_fail</link>()</function> are notfatal to <function><link linkend="my-function-that-can-fail">my_function_that_can_fail</link>()</function>:<informalexample><programlisting>gbooleanmy_function_that_can_fail (GError **err){ GError *tmp_error; g_return_val_if_fail (err == NULL || *err == NULL, FALSE); sub_function_that_can_fail (NULL); /* ignore errors */ tmp_error = NULL; other_function_that_can_fail (&tmp_error); if (tmp_error != NULL) { g_propagate_error (err, tmp_error); return FALSE; }}</programlisting></informalexample></para><para>Note that passing <literal>NULL</literal> for the error location <emphasis>ignores</emphasis>errors; it's equivalent to <literal>try { <link linkend="sub-function-that-can-fail">sub_function_that_can_fail</link>(); } catch(...) {}</literal> in C++. It does <emphasis>not</emphasis> mean to leave errorsunhandled; it means to handle them by doing nothing.</para><para>Error domains and codes are conventionally named as follows:<itemizedlist><listitem><para>The error domain is called<literal><NAMESPACE>_<MODULE>_ERROR</literal>, for example<literal>G_EXEC_ERROR</literal> or <literal>G_THREAD_ERROR</literal>.</para></listitem><listitem><para>The error codes are in an enumeration called <literal><Namespace>_<Module>_Error</literal>; for example,<link linkend="GThreadError">GThreadError</link> or <link linkend="GSpawnError">GSpawnError</link>.</para></listitem><listitem><para>Members of the error code enumeration are called <literal><NAMESPACE>_<MODULE>_ERROR_<CODE></literal>, for example <literal>G_SPAWN_ERROR_FORK</literal> or <literal>G_THREAD_ERROR_AGAIN</literal>. </para></listitem><listitem><para>If there's a "generic" or "unknown" error code for unrecoverable errors itdoesn't make sense to distinguish with specific codes, it should be called <literal><NAMESPACE>_<MODULE>_ERROR_FAILED</literal>, for example <literal>G_SPAWN_ERROR_FAILED</literal> or <literal>G_THREAD_ERROR_FAILED</literal>.</para></listitem></itemizedlist></para><para>Summary of rules for use of <link linkend="GError">GError</link>: <itemizedlist> <listitem> <para> Do not report programming errors via <link linkend="GError">GError</link>. </para> </listitem> <listitem> <para> The last argument of a function that returns an error should be a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -