1 GQuark概念

Quark 是字符串和整数标识符之间的关联。给定字符串或 GQuark 标识符,可以检索到另一个。

Quark 被用于数据集和键控数据列表。

要从字符串创建一个新的 quark,请使用 g_quark_from_string() 或 g_quark_from_static_string()。

要找到与给定 GQuark 对应的字符串,请使用 g_quark_to_string()。

要找到与给定字符串对应的 GQuark,请使用 g_quark_try_string()。

用于 quark 函数的字符串池的另一个用途是字符串规范化,使用 g_intern_string() 或 g_intern_static_string()。规范化的字符串是字符串的规范表示。规范化字符串的一个重要优点是它们可以通过简单的指针比较来比较是否相等,而不是使用 strcmp()。

总结:

  1. GQuark 是32位无符号整形,没有与任何字符串关联的时候,该值为</span>

  2. GQuark 在GLib中没有注册对象 G_QUARK,没有引用计数。没有任何创建和解引用GQuark函数。因为在GLib库初始化的时候会创建一个 quark_ht 哈希表,该哈希表存储,key = stringvalue = quark

  3. GQuark 所有函数都是多线程安全的。

  4. 为什么没有任何创建和解引用函数可调用?

    答:因为GQuark内部使用的是哈希表,该哈希表整个进程只会创建一个,所以内存不会重复创建。

2 g_quark_from_string 和 g_quark_from_static_string区别

g_quark_from_string 和 g_quark_from_static_string 是 GLib 中的两个函数,用于创建或获取与特定字符串相关联的 GQuark(一种唯一的整数标识符)。尽管它们的功能相似,但主要区别在于它们处理字符串内存的方式

2.1 g_quark_from_string

  • 当你传递一个字符串给 g_quark_from_string 时,该函数会为传入的字符串创建一个内部副本(副本内存有GLib系统管理,不需要手动释放)

  • 这意味着,即使原始字符串稍后被修改或释放,与该字符串相关联的 GQuark 仍然有效。

  • 这个函数适合用于动态分配的字符串或其内容可能会改变的字符串。

2.2 g_quark_from_static_string

  • 与 g_quark_from_string 不同,g_quark_from_static_string 不会为传入的字符串创建副本。

  • 它假设传入的字符串是静态的或者至少在 GQuark 使用期间不会改变或被释放。

  • 这个函数的性能可能略优于 g_quark_from_string,因为它避免了字符串复制的开销。

  • 你应该只在确定字符串在整个程序运行期间都不会改变时使用这个函数(例如,使用字面量字符串)。

2.3 小结

测试程序:/assets/GLibStudy/01_GQuark/sample.c

2.3.1 字符串注册GQuark

g_quark_from_stringg_quark_from_static_string 调用的核心函数如下,区别就是是否进行拷贝一份字符串副本。由于动态字符串能够修改,所以需要拷贝一份副本。

/**
 * 区别在于duplicate参数,是否拷贝一份字符串
*/
static inline GQuark
quark_from_string (const gchar *string,
                   gboolean     duplicate)
{
  GQuark quark = 0;
  /* 从系统哈希表获取字符串quark值 */
  quark = GPOINTER_TO_UINT (g_hash_table_lookup (quark_ht, string));

  if (!quark)
    {
      quark = quark_new (duplicate ? quark_strdup (string) : (gchar *)string);
      TRACE(GLIB_QUARK_NEW(string, quark));
    }

  return quark;
}

2.3.2 通过已经注册的字符串获取GQuark

g_quark_try_string 函数是通过传入的字符串获取已经分配的 GQuark。如果没有找到对应的 GQuark 将返回 0

GQuark
g_quark_try_string (const gchar *string)
{
  GQuark quark = 0;

  if (string == NULL)
    return 0;

  G_LOCK (quark_global);
  quark = GPOINTER_TO_UINT (g_hash_table_lookup (quark_ht, string));
  G_UNLOCK (quark_global);

  return quark;
}

GQuark本质是通过哈希表存储对应的字符串和该字符串对应的Quark值。如果非字符串常量调用了 g_quark_from_static_string,如果修改了字符串,哈希存储的字符串内容也会修改,应该哈希表存储的是字符串的地址。这就是 sample.c文件中,修改了字符串之后,找不到Quark的缘由。

3 规范化函数

规范化函数调用后,返回的字符串地址都一样。(即便是堆上申请内存创建的)

g_intern_stringg_intern_static_string 本质上也是调用 quark_from_string 函数。

  • 如果先使用 g_intern_static_string 规范化后的字符串地址是常量字符串地址。

  • 如果先使用 g_intern_string 规范化后的字符串地址是GQuark内部拷贝的字符串副本地址。

测试程序:/assets/GLibStudy/01_GQuark/intern.c