GVariant 格式字符串
GVariant 格式字符串
可变参数转换
本页尝试介绍如何使用 GVariant 来执行可变参数转换。
转换根据格式字符串进行。格式字符串是单个 GVariant 值与一个或多个 C 值之间的双向映射。
使用 g_variant_new() 函数将 C 值转换为 GVariant 值。使用 g_variant_get() 函数将 GVariant 转换为 C 值。
语法
本节详尽地描述了 GVariant 格式字符串的所有可能性。除了此处描述的内容之外,格式字符串不存在其他有效形式。请注意,格式字符串语法将来可能会扩展。
有效的格式字符串具有以下之一的 形式
- 任意类型 字符串
- 以 @前缀的类型字符串
- &s、- &o、- &g、- ^as、- ^a&s、- ^ao、- ^a&o、- ^ay、- ^&ay、- ^aay或- ^a&ay。
- 任意格式字符串,以 m为前缀
- 由零个或多个格式字符串组成、链接并用 括号括起来的序列
- 一个开头大括号,后面是两个格式字符串,然后是一个结尾大括号(受约束的是,第一个格式字符串对应于有效的用于字典的键类型)
符号
下表描述了 GVariant 格式字符串中可能出现的符号的粗略含义。每个符号都在其自己的一节中进行了详细描述,包括使用 示例。
| 符号 | 含义 | 
|---|---|
| b、y、n、q、i、u、x、t、h、d | 用于构建或解构布尔、字节和数字类型。请参见下文的 数字类型。 | 
| s、o、g | 用于构建或解构字符串类型。请参见下文的 字符串。 | 
| v | 用于构建或解构变体类型。请参见下文的 变体。 | 
| a | 用于构建或解构数组。请参见下文的 数组。 | 
| m | 用于构建或解构可能类型。请参见下文的 可能类型。 | 
| () | 用于构建或解构元组。请参见下文的 元组。 | 
| {} | 用于构建或解构字典项。请参见下文的 字典。 | 
| @ | 用作 GVariant类型字符串的前缀(不是格式字符串的前缀,因此as是有效的格式字符串,但@^as不是)。表示应该使用指向GVariant的指针来代替常规 C 类型或类型。对于g_variant_new(),这意味着你必须传递一个非NULL的(GVariant *);如果是浮动引用,则将采用所有权,就像使用g_variant_ref_sink()一样。对于g_variant_get(),这意味着你必须传递一个指向(GVariant *)的指针,以便通过引用返回该值,或者传递NULL来忽略该值。请参见下文的GVariant *。 | 
| *、?、r | 与 @*、@?和r完全等效。仅供完整性提供,以便所有GVariant类型字符串也可用作格式字符串。请参见下面的GVariant *。 | 
| & | 用作 GVariant类型字符串的前缀(不是格式字符串的前缀,因此&s是有效的格式字符串,但&s“ 不是)。表示应该使用指向序列化数据的 C 指针,而不是正常的 C 类型。请参见下面的 指针。 | 
| ^ | 用作某些特定类型格式字符串的前缀。请参见下面的 便捷转换。 | 
数值类型
字符:b、y、n、q、i、u、x、t、h、d
从数值类型进行的可变参数转换以最明显的方式进行。遇到其中一个字符时,g_variant_new() 将等效的 C 类型作为参数。g_variant_get() 获取一个指针,该指针指向等效的 C 类型(或 NULL 以忽略值)。
等效的 C 类型如下
| 字符 | 等效的 C 类型 | 
|---|---|
| b | gboolean | 
| y | guchar | 
| n | gint16 | 
| q | guint16 | 
| i | gint32 | 
| u | guint32 | 
| x | gint64 | 
| t | guint64 | 
| h | gint32(句柄) | 
| d | gdouble | 
 请注意,在 C 中,可变参数列表中的小整数类型会根据需要提升到 int 或 unsigned int,并相应地读回。GLib 当前支持的每个平台上的 int 都是 32 位。这意味着你可以对类型为 int 的 C 表达式与 g_variant_new() 和格式字符 b、y、n、q、i、u 和 h 一起使用。具体来说,你可以对这些字符使用整数字面量。
当使用 x 和 t 字符时,你必须确保提供的价值为 64 位。这意味着你应使用强制转换或使用 G_GINT64_CONSTANT 或 G_GUINT64_CONSTANT 宏。
使用 g_variant_get() 时不会进行类型提升,因为它使用指针。指针必须始终指向确切合适大小的内存区域。
示例
GVariant *value1, *value2, *value3, *value4;
value1 = g_variant_new ("y", 200);
value2 = g_variant_new ("b", TRUE);
value3 = g_variant_new ("d", 37.5):
value4 = g_variant_new ("x", G_GINT64_CONSTANT (998877665544332211));
{
  gdouble floating;
  gboolean truth;
  gint64 bignum;
  g_variant_get (value1, "y", NULL);      /* ignore the value. */
  g_variant_get (value2, "b", &truth);
  g_variant_get (value3, "d", &floating);
  g_variant_get (value4, "x", &bignum);
}
字符串
字符:s、o、g
字符串转换在标准空终止的 C 字符串之间进行。在格式字符串中遇到 s、o 或 g 时,g_variant_new() 会获取 (const gchar *) 并复制一份。NULL 不是有效的字符串;使用可能类型对其进行编码。如果使用 o 或 g 字符,则必须注意确保传递的字符串分别是有效的 D-Bus 对象路径或 D-Bus 类型签名。
在遇到 s、o 或 g 时,g_variant_get() 会获取一个指向 (gchar *)(即:(gchar **))的指针,并将其设置为字符串的新分配副本。使用 g_free() 释放此副本是适当的。还可以传递 NULL 以指示应忽略字符串的值(在这种情况下,不进行复制)。
示例
GVariant *value1, *value2, *value3;
value1 = g_variant_new ("s", "hello world!");
value2 = g_variant_new ("o", "/must/be/a/valid/path");
value3 = g_variant_new ("g", "iias");
#if 0
  g_variant_new ("s", NULL);      /* not valid: NULL is not a string. */
#endif
{
  gchar *result;
  g_variant_get (value1, "s", &result);
  g_print ("It was '%s'\n", result);
  g_free (result);
}
变体
字符:v
在遇到 v 时,g_variant_new() 会获取一个 (GVariant *)。GVariant 的值用作变体值的内容。
在遇到一个v时,g_variant_get()将取用一个指向(GVariant *)(即:(GVariant **))的指针。它被设为一个包含变体值内容的GVariant实例的新引用。使用g_variant_unref()来释放此引用是合适的。还可以传递NULL来表示应忽略该值(在这种情况下,不会创建任何新引用)。
示例
GVariant *x, *y;
/* the following two lines are equivalent: */
x = g_variant_new ("v", y);
x = g_variant_new_variant (y);
/* as are these: */
g_variant_get (x, "v", &y);
y = g_variant_get_variant (x);
数组
字符:a
在遇到一个后面跟着类型字符串的a字符时,g_variant_new()将取用一个已创建为类型的数组的数组生成器的(GVariantBuilder *)。在生成器上将调用g_variant_builder_end()并将结果用作值。作为特例,如果给定的类型字符串是明确类型,则可以赋予NULL来表示该类型的空数组。
在遇到一个后面跟着类型字符串的a字符时,g_variant_get()将取用一个指向一个(GVariantIter *)(即:(GVariantIter **))的指针。将创建并返回一个新的堆分配的迭代器,它已初始化为对数组的元素进行迭代。使用g_variant_iter_free()在完成使用后应释放此迭代器。还可以赋予NULL来表示应忽略数组的值。
示例
GVariantBuilder *builder;
GVariant *value;
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
g_variant_builder_add (builder, "s", "when");
g_variant_builder_add (builder, "s", "in");
g_variant_builder_add (builder, "s", "the");
g_variant_builder_add (builder, "s", "course");
value = g_variant_new ("as", builder);
g_variant_builder_unref (builder);
{
  GVariantIter *iter;
  gchar *str;
  g_variant_get (value, "as", &iter);
  while (g_variant_iter_loop (iter, "s", &str))
    g_print ("%s\n", str);
  g_variant_iter_free (iter);
}
g_variant_unref (value);
Maybe 类型
字符:m
Maybe 类型根据 m 后面的格式字符串以两种不同的方式进行处理。目前使用哪种方法完全取决于 m 后面的字符。
第一种方法适用于从 a、s、o、g、v、@、*、?、r、& 或 ^ 开始的格式字符串。在所有这些情况下,对于非 Maybe 类型,g_variant_new() 取用一个指向非 NULL 值的指针,g_variant_get() 返回(通过引用)一个非 NULL 指针。当其中任何格式字符串的前缀为 m 时,收集的参数类型不会以任何方式改变,但 NULL 变为允许值,以表示 Nothing 情况。
请注意,在数组部分中为构建空数组而引入的“特例”在此处被忽略了。对使用格式字符串 mas  的 NULL 指针的构造是一个 Nothing 值 - 而不是空数组。
第二种方法适用于所有其他格式字符串。对于 g_variant_new() 将收集一个额外的 gboolean 参数,对于 g_variant_get() 将收集一个额外的 (gboolean *)。在此参数之后,将收集为等效的非 Maybe 类型正常收集的参数。
如果向 g_variant_new() 传入 FALSE,则将构造 Nothing 值且将忽略收集的参数。否则(如果传入 TRUE),将按正常方式使用这些参数来创建 Just 值。
如果向 g_variant_get() 传递 NULL,则将忽略该值。如果传递一个非 NULL 指针,则会使用该指针通过引用返回该值是否为 Just。如果该值是 Just,则会将 gboolean 设置为 TRUE 并将该值按通常方式存储在参数中。如果该值是 Nothing,则会将 gboolean 设置为 FALSE 且将按正常方式收集这些参数,但会将它们的值设置为二进制零。
示例
GVariant *value1, *value2, *value3, *value4, *value5, *value6;
value1 = g_variant_new ("ms", "Hello world");
value2 = g_variant_new ("ms", NULL);
value3 = g_variant_new ("(m(ii)s)", TRUE, 123, 456, "Done");
value4 = g_variant_new ("(m(ii)s)", FALSE, -1, -1, "Done");          /* both '-1' are ignored. */
value5 = g_variant_new ("(m@(ii)s)", NULL, "Done");
{
  GVariant *contents;
  const gchar *cstr;
  gboolean just;
  gint32 x, y;
  gchar *str;
  g_variant_get (value1, "ms", &str);
  if (str != NULL)
    g_print ("str: %s\n", str);
  else
    g_print ("it was null\n");
  g_free (str);
  g_variant_get (value2, "m&s", &cstr);
  if (cstr != NULL)
    g_print ("str: %s\n", cstr);
  else
    g_print ("it was null\n");
  /* don't free 'cstr' */
  /* NULL passed for the gboolean *, but two 'gint32 *' still collected */
  g_variant_get (value3, "(m(ii)s)", NULL, NULL, NULL, &str);
  g_print ("string is %s\n", str);
  g_free (str);
  /* note: &s used, so g_free() not needed */
  g_variant_get (value4, "(m(ii)&s)", &just, &x, &y, &cstr);
  if (just)
    g_print ("it was (%d, %d)\n", x, y);
  else
    g_print ("it was null\n");
  g_print ("string is %s\n", cstr);
  /* don't free 'cstr' */
  g_variant_get (value5, "(m*s)", &contents, NULL); /* ignore the string. */
  if (contents != NULL)
    {
      g_variant_get (contents, "(ii)", &x, &y);
      g_print ("it was (%d, %d)\n", x, y);
      g_variant_unref (contents);
    }
  else
    g_print ("it was null\n");
}
元组
字符:()
从左到右处理元组中的每个项目,即可处理元组。每个项目按照惯例处理。
示例
GVariant *value1, *value2;
value1 = g_variant_new ("(s(ii))", "Hello", 55, 77);
value2 = g_variant_new ("()");
{
  gchar *string;
  gint x, y;
  g_variant_get (value1, "(s(ii))", &string, &x, &y);
  g_print ("%s, %d, %d\n", string, x, y);
  g_free (string);
  g_variant_get (value2, "()");   /* do nothing... */
}
GVariant *
字符:@、*、?、r
遇到类型字符串前面的 @ 时,g_variant_new() 接受指向 GVariant 的非 NULL 指针,并直接使用其值,而不会收集参数创建值。提供的 GVariant 必须具有与 @ 之后的类型字符串匹配的类型。* 与 @* 相同(即:获取任何类型的 GVariant)。? 与 @? 相同(即:获取任何基本类型的 GVariant)。r 与 r 相同(即:获取任何元组类型的 GVariant)。
在类型字符串前面遇到 @ 时,g_variant_get() 接受指向 (GVariant *)(即 (GVariant **))的指针,并将其设置为对包含值的 GVariant 的新引用(而不是按照惯例将值解构成 C 类型)。可以提供 NULL 来忽略值。*、? 和 r 以类似于上述内容的方式处理。
你可以始终将 * 用作 ?、r 或任何 @ 用法的替代。但是,如果可能的话,建议使用其他字符,因为这可以提高类型安全性和代码自注释性。
示例
GVariant *value1, *value2;
value1 = g_variant_new ("(i@ii)", 44, g_variant_new_int32 (55), 66);
/* note: consumes floating reference count on 'value1' */
value2 = g_variant_new ("(@(iii)*)", value1, g_variant_new_string ("foo"));
{
  const gchar *string;
  GVariant *tmp;
  gsize length;
  gint x, y, z;
  g_variant_get (value2, "((iii)*)", &x, &y, &z, &tmp);
  string = g_variant_get_string (tmp, &length);
  g_print ("it is %d %d %d %s (length=%d)\n", x, y, z, string, (int) length);
  g_variant_unref (tmp);
  /* quick way to skip all the values in a tuple */
  g_variant_get (value2, "(rs)", NULL, &string); /* or "(@(iii)s)" */
  g_print ("i only got the string: %s\n", string);
  g_free (string);
}
字典
字符:{}
通过首先处理键,然后处理值来处理字典条目。每个值都按照惯例处理。
示例
GVariantBuilder *b;
GVariant *dict;
b = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (b, "{sv}", "name", g_variant_new_string ("foo"));
g_variant_builder_add (b, "{sv}", "timeout", g_variant_new_int32 (10));
dict = g_variant_builder_end (b);
可以通过变量来提取嵌套字典中的数据。
示例
GVariant *data;
gint value = 1;
gint max = 3;
/* type (oa{sa{sv}) */
data = g_variant_new_parsed ("(%o, {'brightness': {'value': <%i>, 'max': <%i>}})",
                             "/object/path", value, max);
{
  GVariant *params;
  GVariant *p_brightness;
  gchar *obj
  gint p_max;
  g_variant_get (data, "(o@a{?*})", &obj, ¶ms);
  g_print ("object_path: %s\n", obj);
  p_brightness = g_variant_lookup_value (params, "brightness", G_VARIANT_TYPE_VARDICT);
  g_variant_lookup (p_brightness, "max", "i", &p_max);
  g_print ("max: %d\n", p_max);
}
指针
字符:&
& 字符用于指示已序列化的数据应通过指针直接交换。
目前,此字符的唯一用法是将其应用于字符串(即:&s、&o 或 &g)。对于 g_variant_new(),这完全不起作用。字符串通常按收集和复制。对于 g_variant_get(),表示它不会创建一个新分配的字符串副本,而是返回已序列化的数据的指针。不应释放此指针。将执行有效性检查,以确保字符串数据始终正确以 null 结尾。
示例
{
  const gchar *str;
  GVariant *value;
  value = g_variant_new ("&s", "hello world");
  g_variant_get (value, "&s", &str);
  g_print ("string is: %s\n", str);
  /* no need to free str */
}
便利转换
字符:^
^ 字符目前支持与字节字符串转换,或与字符串或字节字符串数组转换。不支持字节数组。它有多种形式。
使用 g_variant_new() 时,所有形式从可变参数中收集一个指针值并将其传递给一个函数(如下表所示)。该函数的结果用作此位置的值。使用 g_variant_get() 时,一个指针值通过使用该函数(在表中给出)产生并通过引用返回。
| 转换 | 与 g_variant_new()搭配使用 | 与 g_variant_get()搭配使用 | 
|---|---|---|
| ^as | 相当于 g_variant_new_strv() | 相当于 g_variant_dup_strv() | 
| ^a&s | 相当于 g_variant_get_strv() | |
| ^ao | 相当于 g_variant_new_objv() | 相当于 g_variant_dup_objv() | 
| ^a&o | 相当于 g_variant_get_objv() | |
| ^ay | 相当于 g_variant_new_bytestring() | 等同于 g_variant_dup_bytestring() | 
| ^&ay | 等同于 g_variant_get_bytestring() | |
| ^aay | 等同于 g_variant_new_bytestring_array() | 等同于 g_variant_dup_bytestring_array() | 
| ^a&ay | 等同于 g_variant_get_bytestring_array() |