glib库宏G_DISABLE_CHECKS

本文详细介绍了GLib库中的断言和返回检查宏,如g_return_if_fail和g_return_val_if_fail,用于验证函数预条件并在失败时提供调试信息。文章解释了这些宏在不同编译配置下的行为,并指导如何使用环境变量进行调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifdef G_DISABLE_CHECKS

/**
 * g_return_if_fail:
 * @expr: the expression to check
 *
 * Verifies that the expression @expr, usually representing a precondition,
 * evaluates to %TRUE. If the function returns a value, use
 * g_return_val_if_fail() instead.
 *
 * If @expr evaluates to %FALSE, the current function should be considered to
 * have undefined behaviour (a programmer error). The only correct solution
 * to such an error is to change the module that is calling the current
 * function, so that it avoids this incorrect call.
 *
 * To make this undefined behaviour visible, if @expr evaluates to %FALSE,
 * the result is usually that a critical message is logged and the current
 * function returns.
 *
 * If `G_DISABLE_CHECKS` is defined then the check is not performed.  You
 * should therefore not depend on any side effects of @expr.
 *
 * To debug failure of a g_return_if_fail() check, run the code under a debugger
 * with `G_DEBUG=fatal-criticals` or `G_DEBUG=fatal-warnings` defined in the
 * environment (see [Running GLib Applications](glib-running.html)):
 *
 * |[
 *   G_DEBUG=fatal-warnings gdb ./my-program
 * ]|
 *
 * Any unrelated failures can be skipped over in
 * [gdb](https://www.gnu.org/software/gdb/) using the `continue` command.
 */
#define g_return_if_fail(expr) G_STMT_START{ (void)0; }G_STMT_END

/**
 * g_return_val_if_fail:
 * @expr: the expression to check
 * @val: the value to return from the current function
 *       if the expression is not true
 *
 * Verifies that the expression @expr, usually representing a precondition,
 * evaluates to %TRUE. If the function does not return a value, use
 * g_return_if_fail() instead.
 *
 * If @expr evaluates to %FALSE, the current function should be considered to
 * have undefined behaviour (a programmer error). The only correct solution
 * to such an error is to change the module that is calling the current
 * function, so that it avoids this incorrect call.
 *
 * To make this undefined behaviour visible, if @expr evaluates to %FALSE,
 * the result is usually that a critical message is logged and @val is
 * returned from the current function.
 *
 * If `G_DISABLE_CHECKS` is defined then the check is not performed.  You
 * should therefore not depend on any side effects of @expr.
 *
 * See g_return_if_fail() for guidance on how to debug failure of this check.
 */
#define g_return_val_if_fail(expr,val) G_STMT_START{ (void)0; }G_STMT_END

/**
 * g_return_if_reached:
 *
 * Logs a critical message and returns from the current function.
 * This can only be used in functions which do not return a value.
 *
 * See g_return_if_fail() for guidance on how to debug failure of this check.
 */
#define g_return_if_reached() G_STMT_START{ return; }G_STMT_END

/**
 * g_return_val_if_reached:
 * @val: the value to return from the current function
 *
 * Logs a critical message and returns @val.
 *
 * See g_return_if_fail() for guidance on how to debug failure of this check.
 */
#define g_return_val_if_reached(val) G_STMT_START{ return (val); }G_STMT_END

#else /* !G_DISABLE_CHECKS */

#define g_return_if_fail(expr)        G_STMT_START{            \
     if G_LIKELY(expr) { } else                           \
       {                                \
     g_return_if_fail_warning (G_LOG_DOMAIN,            \
                           G_STRFUNC,                \
                           #expr);                \
     return;                            \
       };                }G_STMT_END

#define g_return_val_if_fail(expr,val)    G_STMT_START{            \
     if G_LIKELY(expr) { } else                        \
       {                                \
     g_return_if_fail_warning (G_LOG_DOMAIN,            \
                           G_STRFUNC,                \
                           #expr);                \
     return (val);                            \
       };                }G_STMT_END

#define g_return_if_reached()        G_STMT_START{            \
     g_log (G_LOG_DOMAIN,                        \
        G_LOG_LEVEL_CRITICAL,                    \
        "file %s: line %d (%s): should not be reached",        \
        __FILE__,                            \
        __LINE__,                            \
        G_STRFUNC);                            \
     return;                }G_STMT_END

#define g_return_val_if_reached(val)    G_STMT_START{            \
     g_log (G_LOG_DOMAIN,                        \
        G_LOG_LEVEL_CRITICAL,                    \
        "file %s: line %d (%s): should not be reached",        \
        __FILE__,                            \
        __LINE__,                            \
        G_STRFUNC);                            \
     return (val);            }G_STMT_END

#endif /* !G_DISABLE_CHECKS */
 

在makefile中 --enable-debug={no,mininum,yes}可以控制此开关

--enable-debug Turns on various amounts of debugging support. Setting this to 'no' disables g_assert(), g_return_if_fail(), g_return_val_if_fail() and all cast checks between different object types. Setting it to 'minimum' disables only cast checks. Setting it to 'yes' enables runtime debugging. The default is 'minimum'. Note that 'no' is fast, but dangerous as it tends to destabilize even mostly bug-free software by changing the effect of many bugs from simple warnings into fatal crashes. Thus--enable-debug=no should not be used for stable releases of GLib.

<think>我们正在讨论GLib中的g_variant_get函数。根据用户的需求,他想要了解g_variant_get的使用方法和文档示例。 首先,我们需要明确g_variant_get函数的作用:它用于从GVariant实例中提取值。GVariant是GLib中用于处理类型化数据的一种机制,类似于一种通用的容器,可以存储各种类型的数据(包括基本类型、数组、元组等)。 函数原型: ```c void g_variant_get (GVariant *value, const gchar *format_string, ...); ``` 这个函数使用格式字符串(类似于scanf或printf的格式)来指定要提取的数据类型和数量,然后通过可变参数传递指向存储这些值的变量的指针。 注意事项: - 调用g_variant_get之前,必须确保GVariant实例的类型与格式字符串匹配,否则会导致未定义行为。 - 对于容器类型(如数组、元组等),可能需要递归地使用g_variant_get来提取内部的值。 接下来,我们给出一个使用示例。假设我们有一个GVariant,它包含一个元组,元组中有一个字符串和一个整数: ```c // 假设我们有一个GVariant*变量,名为variant,其类型为"(si)",即一个字符串和一个整数组成的元组。 const gchar *str; gint32 num; g_variant_get(variant, "(si)", &str, &num); // 注意:字符串是直接指向GVariant内部数据的,所以不需要释放,但要注意GVariant的生命周期。 ``` 另一个例子,提取一个字符串数组(类型为"as"): ```c GVariant *array_var = ...; // 类型为 as (字符串数组) gchar **strv; gsize length; // 使用格式字符串"^a&s"来获取字符串数组,其中'^'表示返回一个NULL结尾的数组,'a'表示数组,'&s'表示字符串(gchar*) g_variant_get(array_var, "^a&s", &strv); // 使用strv,注意最后需要释放strv(因为使用了'&s',所以每个字符串都是新分配的,整个数组也需要释放) g_strfreev(strv); ``` 但是注意,上面的例子中,我们使用了"^a&s",这表示我们想要一个以NULL结尾的字符串数组,并且每个字符串都是新分配的(因此需要释放)。如果我们使用"as",那么我们将得到一个指向GVariant内部数组的指针,并且不需要释放,但必须注意GVariant的生命周期。 因此,使用g_variant_get时,格式字符串的写法非常重要,它决定了如何解释数据以及内存管理的方式。 关于文档,可以参考GLib官方文档:https://developer.gnome.org/glib/stable/glib-GVariant.html#g-variant-get 在文档中,详细列出了格式字符串的语法,包括: - 基本类型:b(gboolean)、y(guint8)、n(gint16)、q(guint16)、i(gint32)、u(guint32)、x(gint64)、t(guint64)、d(gdouble)、h(gint32,文件描述符)、s(字符串,const gchar*)、o(对象路径,字符串)、g(类型字符串,字符串)、v(GVariant*,任意类型)等。 - 容器类型:a(数组)、m(maybe)、()(元组)、{}(字典条目)、r(元组,与()相同)等。 - 修饰符:&(表示传递一个指向数据的指针,而不是数据本身;对于字符串,表示不复制,直接引用内部数据)、@(传递一个GVariant*并增加引用计数)、^(表示返回一个以NULL结尾的数组)等。 因此,在使用g_variant_get时,必须根据GVariant的实际类型和需要的内存管理方式来编写格式字符串。 下面,我们给出一个更复杂的例子:提取一个字典(类型为a{sv},即键为字符串,值为任意类型的GVariant的字典)中的值。 ```c GVariant *dict_var = ...; // 类型为 a{sv} GVariantIter iter; const gchar *key; GVariant *value; g_variant_iter_init(&iter, dict_var); while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) { // 处理每个键值对 // 注意:key是内部引用,不需要释放;value是一个GVariant,使用完后需要解除引用 g_print("Key: %s, Value type: %s\n", key, g_variant_get_type_string(value)); g_variant_unref(value); } ``` 在上面的例子中,我们使用了迭代器来遍历字典。格式字符串"{&sv}"表示一个字典条目(由花括号表示),其中&s表示键是一个字符串(内部引用),v表示值是一个GVariant*(需要调用g_variant_unref释放)。 最后,需要提醒的是,由于g_variant_get使用可变参数,因此类型必须严格匹配,否则可能导致程序崩溃。建议在调用前使用g_variant_is_of_type或g_variant_get_type_string检查类型。 根据要求,我们生成相关问题:</think>### GLib `g_variant_get` 使用指南 `g_variant_get()` 是 GLib 中用于从 `GVariant` 对象提取数据的核心函数。其作用类似于 C 语言的 `scanf`,通过**格式字符串**指定要提取的数据类型和顺序。以下是详细说明和示例: #### 函数原型 ```c void g_variant_get (GVariant *value, const gchar *format_string, ...); ``` - **`value`**:包含数据的 `GVariant` 对象 - **`format_string`**:类型格式字符串(见下文说明) - **`...`**:接收提取数据的变量指针列表 --- ### 格式字符串语法 格式字符串由**类型字符**和**修饰符**组成: | 类型 | 字符 | C 类型 | 说明 | |------|------|----------------|--------------------------| | 基本 | `b` | `gboolean` | 布尔值 | | | `y` | `guint8` | 字节 | | | `n` | `gint16` | 有符号16位整数 | | | `q` | `guint16` | 无符号16位整数 | | | `i` | `gint32` | 有符号32位整数 | | | `u` | `guint32` | 无符号32位整数 | | | `x` | `gint64` | 有符号64位整数 | | | `t` | `guint64` | 无符号64位整数 | | | `d` | `gdouble` | 双精度浮点数 | | | `s` | `const gchar*` | UTF-8字符串(非转移所有权)| | 容器 | `a` | - | 数组(如 `ai` 表示 `gint32` 数组) | | | `m` | - | Maybe/可选类型 | | | `()` | - | 元组 | | | `v` | `GVariant*` | 嵌套 variant 对象 | | 修饰 | `&` | - | 传递指针而非值(用于字符串) | | | `@` | - | 增加引用计数 | | | `^` | - | 返回 NULL 结尾的数组 | --- ### 使用示例 #### 1. 提取基本类型 ```c GVariant *var = g_variant_new("(si)", "Hello", 42); // 创建元组 (string, int) const gchar *str; gint32 num; g_variant_get(var, "(si)", &str, &num); // 格式匹配元组结构 g_print("String: %s\nNumber: %d\n", str, num); // 输出: String: Hello, Number: 42 ``` > ⚠️ 注意:字符串 `str` 指向 `GVariant` 内部数据,无需释放但需保证 `var` 有效 #### 2. 提取数组 ```c GVariant *arr = g_variant_new("ai", g_variant_new_int32(10), g_variant_new_int32(20), g_variant_new_int32(30)); // 数组 [10,20,30] gsize len; gint32 *nums; g_variant_get(arr, "ai", &len, &nums); // 格式 'ai' 提取数组长度和指针 for (gsize i = 0; i < len; i++) { g_print("%d ", nums[i]); // 输出: 10 20 30 } g_free(nums); // 需要手动释放数组内存 ``` #### 3. 提取嵌套结构 ```c // 创建嵌套结构:{ "name": (s), "scores": [ai] } GVariant *dict = g_variant_parse( G_VARIANT_TYPE("a{sv}"), "{'name': <'Alice'>, 'scores': <[80, 90]>}", NULL, NULL, NULL ); GVariantIter *iter; gchar *key; GVariant *val; g_variant_get(dict, "a{sv}", &iter); // 迭代字典 while (g_variant_iter_next(iter, "{&sv}", &key, &val)) { if (g_strcmp0(key, "name") == 0) { const gchar *name; g_variant_get(val, "s", &name); g_print("Name: %s\n", name); } else if (g_strcmp0(key, "scores") == 0) { gsize len; gint32 *scores; g_variant_get(val, "ai", &len, &scores); // 处理分数数组... g_free(scores); } g_variant_unref(val); } g_variant_iter_free(iter); ``` --- ### 关键注意事项 1. **格式匹配**:格式字符串必须与 `GVariant` 的实际类型**完全匹配**,否则会导致未定义行为或崩溃[^1]。 2. **内存管理**: - 基本类型(如 `i`, `u`)直接复制值到变量 - 字符串(`s`)返回内部指针,无需释放但受 `GVariant` 生命周期限制 - 数组(如 `ai`)返回新分配的内存,需调用 `g_free()` 释放 - 嵌套 `GVariant*` 需用 `g_variant_unref()` 释放 3. **类型检查**:调用前建议验证类型: ```c if (g_variant_is_of_type(var, G_VARIANT_TYPE("(si)"))) { g_variant_get(var, "(si)", ...); } ``` 官方文档参考:[GVariant Format Strings](https://docs.gtk.org/glib/gvariant-format-strings.html)[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值