⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 error_reporting.sgml

📁 GLib是GTK+和GNOME工程的基础底层核心程序库
💻 SGML
📖 第 1 页 / 共 2 页
字号:
<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 &lt;glib.h&gt;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", &amp;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-&gt;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-&gt;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 (&amp;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 (&amp;tmp_error);  other_function_that_can_fail (&amp;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 (&amp;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>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_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>&lt;Namespace&gt;_&lt;Module&gt;_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>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_ERROR_&lt;CODE&gt;</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>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_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 + -