结构

GLibVariant

自 2.24 起

描述 [src]

struct GVariant {
  /* No available fields */
}

GVariant 是一个变异数据类型;它可以包含一个或多个值以及有关值类型的 信息。

GVariant 可能包含简单类型(如整数或布尔值);或复杂类型(如两个字符串的数组或键值对的字典)。GVariant 也是不可变的:一旦创建,则其类型和内容都不能再进一步 修改。

GVariant 在需要序列化数据时很有用,例如在 D-Bus 中发送方法参数,或在使用 GSettings 保存设置时。

创建新的 GVariant 时,您可以传递要存储在其中的数据以及表示要传递给它的数据类型的字符串。

例如,如果要创建一个保存整数值的 GVariant,可以使用

GVariant *v = g_variant_new ("u", 40);

第一个参数中的字符串 u 告诉 GVariant 传递给构造函数的数据 (40) 将是无符号 整数。

可在 GVariant 格式字符串 的文档中找到更多有关 GVariant 用法的示例。

可能范围由类型确定。

GVariant 使用的类型系统是 GVariantType

GVariant 实例始终有类型和值(它们在构造时间给出)。GVariant 实例的类型和值永远不能改变,除非 GVariant 自身被销毁。GVariant 不能包含指针。

使用 g_variant_ref()g_variant_unref() 计算 GVariant 的引用。GVariant 还有浮动引用计数——见 g_variant_ref_sink()

GVariant 完全是线程安全的。任何数量的线程都可以从任何方式同时访问 GVariant 实例,而没有问题。

GVariant 进行了大量的优化,以处理序列化形式的数据。它特别适合位于内存映射文件中的数据。它可以在一个小常数时间内执行几乎所有反序列化操作,通常只接触单个内存页。序列化的 GVariant 数据还可以通过网络发送。

GVariant 在很大程度上与 D-Bus 兼容。几乎所有类型的 GVariant 实例都可以通过 D-Bus 发送。有关异常,请参见 GVariantType。(但是,GVariant 的序列化格式与 D-Bus 消息正文的序列化格式不同:对于那些,请使用 GIO 库中的 GDBusMessage。)

出于空间效率,GVariant 序列化格式不会自动包含变体长度、类型或字节序,这些必须从上下文推断出来(例如,知道特定文件格式总是包含一个占用整个文件长度的 little-endian G_VARIANT_TYPE_VARIANT)或从外部提供(例如,可以将一个长度、类型和/或字节序指示器放在文件开头、网络消息或网络流中)。

GVariant 的大小主要受到任何较低级别的操作系统约束的限制,例如 gsize 中的位数。例如,使用 GMappedFile2GB 文件映射到内存中并调用其 g_variant_new_from_data() 是合理的。

为方便 C 编程人员,GVariant 具有功能强大的基于变长参数的值构造和析构。此功能设计为可嵌入其他库中。

有一种受 Python 启发的文本语言用于描述 GVariant 值。GVariant 包括此语言的打印机和带有类型推断的解析器。

内存使用情况

GVariant 尝试在内存使用方面非常高效。本部分大致介绍了当前实现使用多少内存。此处的信息将来可能会更改。

GVariant 分配的内存可以分为 4 个广泛的目的:序列化数据内存、类型信息缓存内存、缓冲区管理内存以及 GVariant 结构自身内存。

序列化数据内存

这是用于以序列化形式存储 GVariant 数据的内存。这就是在网络上传输的内容,或最终进入磁盘的内容,而不计算任何字节序指示器,或顶层变体的长度或类型。

存储布尔值所需的内存量为 1 字节。16、32 和 64 位整数和双精度浮点数使用它们的“自然”大小。字符串(包括对象路径和签名字符串)存储有空终止符,因此使用字符串的长度加 1 字节。

“Maybe” 类型根本不使用任何空间就能表示空值,并且使用与等效的非 maybe 类型的值相同数量的空间(有时再加一个字节)来表示非空情况。

数组使用存储各个成员所需的空间,这些成员被串联起来。此外,如果存储在数组中的项不是固定大小(例如:字符串、其他数组等),那么将为每一项存储一个额外的框架偏移量。此偏移量大小为 1、2 或 4 个字节,具体取决于容器的整体大小。此外,为对齐子值所需,还将添加额外的填充字节。

元组(包括字典项)使用存储各个成员所需的空间大小,这些成员被串联起来,加上每个非固定大小项一个框架偏移量(与数组相同),元组中的最后一个项除外。此外,为对齐子值所需,还将添加额外的填充字节。

变体使用的空间大小与变体内的项相同,再加上 1 个字节,以及变体内的项的类型字符串长度。

作为一个示例,考虑一个将字符串映射到变体的字典。如果字典为空,则序列化不需要 0 字节。

如果我们添加项“宽度”,并且将其映射到 500 的 int32 值,那么我们将使用 4 个字节来存储 int32(因此对于包含它的变体来说是 6 个字节),并将 6 个字节用于字符串。在字符串的 6 字节之后,变体必须对齐至 8,因此这需要再添加 2 个字节。6(字符串)+ 2(填充)+ 6(变体)= 14 字节用于字典项。以框架偏移量形式向数组中再添加 1 个字节,总共为 15 个字节。

如果我们添加另一个项“标题”,把它映射到恰好具有空值的一个可空字符串,那么对于空值,我们将使用 0 字节(再使用 3 个字节用于变体以便用它来包含类型字符串),并使用 6 字节用于字符串。同样,我们需要 2 个填充字节。这使得总计为 6 + 2 + 3 = 11 个字节。

我们现在需要在数组中的两个项之间添加额外的填充。在第一个项的 14 字节之后,需要 2 个字节。我们现在需要 2 个框架偏移量再加额外的 2 个字节。14 + 2 + 11 + 2 = 29 字节,用于编码整个两项字典。

类型信息缓存

对于程序中当前存在的每个 GVariant 类型,类型信息结构保存在类型信息缓存中。类型信息结构对于快速反序列化是必需的。

继续上述示例,如果 GVariant 存在于类型 a{sv} 时,那么 a{sv}{sv}sv 的类型信息结构将会存在。相同类型的多次使用将共享相同的类型信息。此外,所有单数字类型都存储在只读静态内存中,并且不计入使用 GVariant 的程序的可写内存占用。

除了存储在只读内存中的类型信息结构之外,还有两种类型的类型信息。一种用于存在单一元素类型的容器类型:数组和 maybe 类型。另一种用于存在多个元素类型的容器类型:元组和字典项。

数组类型信息结构为 6 * sizeof (void *),加上存储类型字符串本身所需内存的大小。这意味着,在 32 位系统中,a{sv} 的缓存项需要 30 个字节的内存(加上分配开销)。

元组类型信息结构是6 * sizeof (void *),外加元组中每一项的4 * sizeof (void *),以及存储类型字符串本身所需的内存。例如,2 项元组的类型信息结构将消耗尺寸为14 * sizeof (void *)(外加类型字符串)的可写内存。这意味着在 32 位系统上,{sv} 的缓存项将需要 61 字节的内存(外加分配开销)。

这意味着,对于我们的a{sv}示例,总共将分配 91 字节的类型信息。

此外,类型信息缓存使用GHashTable 来存储和查找缓存项,并将指向该哈希表的一个指针存储在静态存储器中。类型缓存中没有项时释放哈希表。

虽然这些尺寸看起来可能很大,但是记住一个程序可能只包含非常少数量的不同类型值,并且对于相同类型的许多不同值,只需要一个类型信息结构这一点非常重要。

缓冲区管理内存

GVariant 使用一个内部缓冲区管理结构处理各种可能的序列化数据源。缓冲区负责确保在GVariant 不再使用数据时调用正确的函数。这可能涉及一个g_free() 或甚至g_mapped_file_unref()

对每一块序列化数据使用一个缓冲区管理结构。缓冲区管理结构的尺寸是4 * (void *)。在 32 位系统上,那就是 16 字节。

GVariant 结构

GVariant 结构的尺寸是6 * (void *)。在 32 位系统上,那就是 24 字节。

仅当使用API 调用显式创建时,GVariant 结构才存在。例如,如果根据上面给出的示例(使用词典),从序列化数据构建一个GVariant,那么,尽管构成整个词典的 9 个单独值(两个键、两个值、两个包含值的变体、两个词典项以及词典本身),仅存在一个GVariant 实例 — 即引用词典的实例。

如果发出调用以开始访问其他值,那么仅在这些值正在使用时才存在GVariant 实例(即:直到您调用g_variant_unref())。类型信息是共享的。序列化数据和该序列化数据的缓冲区管理结构由子级共享。

总结

将整个示例放在一起,对于将字符串映射到变体的词典(具有如上给出的两个项),我们将使用 91 个字节的内存作为类型信息,29 个字节的内存作为序列化数据,16 个字节用于缓冲区管理,24 个字节用于GVariant 实例,总计 160 个字节,外加分配开销。如果我们使用g_variant_get_child_value() 来访问这两个词典项,我们将额外使用 48 个字节。如果我们有相同类型的其他词典,我们将为那些词典的序列化数据和缓冲区管理使用更多内存,但类型信息将被共享。

从 2.24 起可用

构造函数

g_variant_new

创建新的GVariant 实例。

自 2.24 起

g_variant_new_array

children 中创建新的GVariant 数组。

自 2.24 起

g_variant_new_boolean

创建一个新的布尔值GVariant实例 — TRUEFALSE

自 2.24 起

g_variant_new_byte

创建一个字节GVariant实例。

自 2.24 起

g_variant_new_bytestring

使用string中的内容创建字节数组GVariant。此函数与g_variant_new_string()类似,只不过该字符串不必是有效的UTF-8。

自:2.26

g_variant_new_bytestring_array

使用给定的字符串数组构造字节串GVariant数组。

自:2.26

g_variant_new_dict_entry

创建新字典项GVariantkeyvalue必须是非NULL值。key必须是基本类型的值(即:不是容器)。

自 2.24 起

g_variant_new_double

创建一个新的双类型GVariant实例。

自 2.24 起

g_variant_new_fixed_array

构造新数组GVariant实例,其中元素的类型为element_type类型。

自:2.32

g_variant_new_from_bytes

构造新序列化模式的GVariant实例。此函数是用于创建新序列化值的新内部接口,由 gvariant.c 中的各种函数调用。

自:2.36

g_variant_new_from_data

从序列化data中创建一个新的GVariant实例。

自 2.24 起

g_variant_new_handle

创建一个句柄GVariant实例。

自 2.24 起

g_variant_new_int16

创建一个新的 int16GVariant实例。

自 2.24 起

g_variant_new_int32

创建一个新的 int32GVariant实例。

自 2.24 起

g_variant_new_int64

创建一个新的 int64GVariant实例。

自 2.24 起

g_variant_new_maybe

根据child是否为NULL,将child包装在 maybe 容器内或针对给定type创建 Nothing 实例。

自 2.24 起

g_variant_new_object_path

使用object_path中的内容创建 D-Bus 对象路径GVariantobject_path必须是一个有效的 D-Bus 对象路径。不确定时,请使用g_variant_is_object_path()

自 2.24 起

g_variant_new_objv

使用给定的字符串数组构造对象路径GVariant数组。

自:2.30

g_variant_new_parsed

解析format并返回结果。

g_variant_new_parsed_va

解析format并返回结果。

g_variant_new_printf

使用 printf 格式化创建一个字符串类型GVariant

自:2.38

g_variant_new_signature

使用string中的内容创建 D-Bus 类型签名GVariantstring必须是一个有效的 D-Bus 类型签名。不确定时,请使用g_variant_is_signature()

自 2.24 起

g_variant_new_string

使用string中的内容创建一个字符串GVariant

自 2.24 起

g_variant_new_strv

使用给定的字符串数组构造字符串GVariant数组。

自 2.24 起

g_variant_new_take_string

使用string中的内容创建一个字符串GVariant

自:2.38

g_variant_new_tuple

children中的项创建一个新的元组GVariant。类型由children的类型确定。children数组中的任何项都不能为NULL

自 2.24 起

g_variant_new_uint16

创建一个新的 uint16GVariant实例。

自 2.24 起

g_variant_new_uint32

创建一个新的 uint32GVariant实例。

自 2.24 起

g_variant_new_uint64

创建一个新的 uint64GVariant实例。

自 2.24 起

g_variant_new_va

此函数是面向基于GVariant的库的,让它们能为用户提供类似 g_variant_new() 的功能。

自 2.24 起

g_variant_new_variant

包装value。结果是一个GVariant实例,表示包含原始值的变体。

自 2.24 起

Functions

g_variant_is_object_path

确定给定的字符串是否是有效的 D-Bus 对象路径。应在将字符串传递给 g_variant_new_object_path() 之前确保字符串是有效的 D-Bus 对象路径。

自 2.24 起

g_variant_is_signature

确定给定的字符串是否是有效的 D-Bus 类型签名。应在将字符串传递给 g_variant_new_signature() 之前确保字符串是有效的 D-Bus 类型签名。

自 2.24 起

g_variant_parse

从文本表示中解析 `GVariant`。

g_variant_parse_error_print_context

漂亮地打印一条信息,显示解析尝试进行字符串中 `GVariant` 解析错误的上下文。

自:2.40

g_variant_parse_error_quark
没有可用说明。

g_variant_parser_get_error_quark

与 g_variant_error_quark() 相同。

已弃用:未知 

实例方法

g_variant_byteswap

对 `value` 的内容执行字节交换操作。结果是 `value` 中包含的所有多字节数字数据都被字节交换。其中包括 16、32 和 64 位有符号和无符号整数,以及文件句柄和双精度浮点值。

自 2.24 起

g_variant_check_format_string

检查使用 `format_string` 在 `value` 上调用 `g_variant_get()` 从类型兼容性的角度来看是否有效。`format_string` 假设是一个有效的格式字符串(从语法角度来看)。

自:2.34

g_variant_classify

根据它的顶级类型对 `value` 进行分类。

自 2.24 起

g_variant_compare

比较 `one` 和 `two`。

自:2.26

g_variant_dup_bytestring

类似 `g_variant_get_bytestring()`,但不会返回常量字符串,而是复制字符串。

自:2.26

g_variant_dup_bytestring_array

获取 `GVariant` 中字节数组数组的内容。此调用进行深度复制;应使用 g_strfreev() 释放返回结果。

自:2.26

g_variant_dup_objv

获取 `GVariant` 中对象路径数组的内容。此调用进行深度复制;应使用 g_strfreev() 释放返回结果。

自:2.30

g_variant_dup_string

类似于 `g_variant_get_string()`,除了返回常量字符串外,该字符串被复制。

自 2.24 起

g_variant_dup_strv

获取 `GVariant` 中字符串数组的内容。此调用进行深度复制;应使用 g_strfreev() 释放返回结果。

自 2.24 起

g_variant_equal

检查 `one` 和 `two` 是否具有相同的类型和值。

自 2.24 起

g_variant_get

解构 `GVariant` 实例。

自 2.24 起

g_variant_get_boolean

返回 `value` 的布尔值。

自 2.24 起

g_variant_get_byte

返回 `value` 的字节值。

自 2.24 起

g_variant_get_bytestring

返回具有字节数组类型 `GVariant` 实例的字符串值。该字符串没有特定的编码。

自:2.26

g_variant_get_bytestring_array

获取 `GVariant` 中字节数组数组的内容。此调用进行浅层复制;应使用 g_free() 释放返回结果,但不能修改各个字符串。

自:2.26

g_variant_get_child

从容器 `GVariant` 实例中读取子项,并根据 `format_string`对其进行解构。此调用本质上是 `g_variant_get_child_value()` 和 g_variant_get() 的组合。

自 2.24 起

g_variant_get_child_value

从容器 `GVariant` 实例中读取子项。其中包括变量、Maybe、数组、元组和字典条目。在任何其他类型的 `GVariant` 上调用此函数都是错误的。

自 2.24 起

g_variant_get_data

返回一个序列化的 GVariant 实例的指针。如果从不可信来源读取,则返回的数据可能不是完全规范化形式。返回的数据无需释放;它在 value 存在的过程中一直有效。

自 2.24 起

g_variant_get_data_as_bytes

返回一个序列化的 GVariant 实例的指针。此函数的语义与 g_variant_get_data() 完全相同,不同之处在于返回的 GBytes 持有一个对变种数据的引用。

自:2.36

g_variant_get_double

返回 value 的双精度浮点值。

自 2.24 起

g_variant_get_fixed_array

提供对固定大小项数组的序列化数据的访问。

自 2.24 起

g_variant_get_handle

返回 value 的 32 位有符号整数值。

自 2.24 起

g_variant_get_int16

返回 value 的 16 位有符号整数值。

自 2.24 起

g_variant_get_int32

返回 value 的 32 位有符号整数值。

自 2.24 起

g_variant_get_int64

返回 value 的 64 位有符号整数值。

自 2.24 起

g_variant_get_maybe

给定一个 maybe 类型的 GVariant 实例,提取它的值。如果值为 Nothing,则此函数返回 NULL

自 2.24 起

g_variant_get_normal_form

获取一个 GVariant 实例,该实例与 value 有相同的值,并且可信为标准格式。

自 2.24 起

g_variant_get_objv

获取一个对象路径 GVariant 数组的内容。此调用进行浅拷贝;应该使用 g_free() 释放返回的结果,但不得修改各个字符串。

自:2.30

g_variant_get_size

确定使用 g_variant_store() 存储 value 所需的字节数。

自 2.24 起

g_variant_get_string

返回带有字符串类型的 GVariant 实例的字符串值。这包括类型 G_VARIANT_TYPE_STRINGG_VARIANT_TYPE_OBJECT_PATHG_VARIANT_TYPE_SIGNATURE

自 2.24 起

g_variant_get_strv

获取一个字符串 GVariant 数组的内容。此调用进行浅拷贝;应该使用 g_free() 释放返回的结果,但不得修改各个字符串。

自 2.24 起

g_variant_get_type

确定 value 的类型。

自 2.24 起

g_variant_get_type_string

返回 value 的类型字符串。这与调用 g_variant_type_peek_string() 的结果不同,此字符串以空结尾。此字符串属于 GVariant,且不得释放。

自 2.24 起

g_variant_get_uint16

返回 value 的 16 位无符号整数值。

自 2.24 起

g_variant_get_uint32

返回 value 的 32 位无符号整数值。

自 2.24 起

g_variant_get_uint64

返回 value 的 64 位无符号整数值。

自 2.24 起

g_variant_get_va

此函数旨在供基于 GVariant 的库使用,这些库希望向其用户提供类似 g_variant_get() 的功能。

自 2.24 起

g_variant_get_variant

拆箱 value。结果是包含在 value 中的 GVariant 实例。

自 2.24 起

g_variant_hash

GVariant 实例生成哈希值。

自 2.24 起

g_variant_is_container

检查 value 是否是一个容器。

自 2.24 起

g_variant_is_floating

检查 value 是否具有浮动引用计数。

自:2.26

g_variant_is_normal_form

检查 value 是否为标准格式。

自 2.24 起

g_variant_is_of_type

检查 value 是否具有与提供的 type 匹配的类型。

自 2.24 起

g_variant_iter_new

value 中的项创建堆分配的 GVariantIter 以进行迭代。

自 2.24 起

g_variant_lookup

在字典 GVariant 中查找一个值。

2.28 起适用

g_variant_lookup_value

在字典 GVariant 中查找一个值。

2.28 起适用

g_variant_n_children

确定容器 GVariant 实例中的子项数。这包括变体、maybe、数组、元组和字典项。在任何其他类型的 GVariant 上调用此函数都会出错。

自 2.24 起

g_variant_print

以 g_variant_parse() 可理解的格式漂亮打印 value

自 2.24 起

g_variant_print_string

行为类似于 g_variant_print(),但对 GString 进行操作。

自 2.24 起

g_variant_ref

增加 value 的引用计数。

自 2.24 起

g_variant_ref_sink

GVariant 使用浮动引用计数系统。所有以 g_variant_new_ 开头的函数的名称都返回浮动引用。

自 2.24 起

g_variant_store

value 的序列化形式存储在 data 处。data 应足够大。请参见 g_variant_get_size()。

自 2.24 起

g_variant_take_ref

如果 value 为浮动,则将其下沉。否则,什么也不做。

g_variant_unref

减少 value 的引用计数。当其引用计数降至 0 时,该变量所用的内存将被释放。

自 2.24 起