我是靠谱客的博主 怕孤独季节,这篇文章主要介绍4_05_GLib库入门与实践_字节数组,现在分享给大家,希望可以做个参考。

简介

GLib提供了三种类型的数组,普通数组,指针数组和字节数组,本节讨论字节数组。
字节数组比普通数组和指针数组最大的不同是它可以存储任意值,甚至包括’’这种只能出现在普通字符串末尾的特殊字符。

数据结构

本节操作的数据结构有两个,一个是GByteArray,一个是GBytes。
GByteArray结构体定义如下:

复制代码
1
2
3
4
5
struct GByteArray { guint8 *data; guint len; };

GBytes结构体对用户不透明。

函数列表

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
GByteArray * g_byte_array_new () GByteArray * g_byte_array_new_take () GByteArray * g_byte_array_sized_new () GByteArray * g_byte_array_ref () void g_byte_array_unref () GByteArray * g_byte_array_append () GByteArray * g_byte_array_prepend () GByteArray * g_byte_array_remove_index () GByteArray * g_byte_array_remove_index_fast () GByteArray * g_byte_array_remove_range () void g_byte_array_sort () void g_byte_array_sort_with_data () GByteArray * g_byte_array_set_size () guint8 * g_byte_array_free () GBytes * g_byte_array_free_to_bytes () GBytes * g_bytes_new () GBytes * g_bytes_new_take () GBytes * g_bytes_new_static () GBytes * g_bytes_new_with_free_func () GBytes * g_bytes_new_from_bytes () gconstpointer g_bytes_get_data () gsize g_bytes_get_size () guint g_bytes_hash () gboolean g_bytes_equal () gint g_bytes_compare () GBytes * g_bytes_ref () void g_bytes_unref () gpointer g_bytes_unref_to_data () GByteArray * g_bytes_unref_to_array ()

函数功能分类

函数功能有三类,一类是对GByteArray字节数组的操作,一类是对GBytes字节的操作,还有一类是GByteArray与GBytes两者转换的操作。

GByteArray字节数组

创建

复制代码
1
2
3
4
5
GByteArray * g_byte_array_new () GByteArray * g_byte_array_new_take () GByteArray * g_byte_array_sized_new () GByteArray * g_byte_array_set_size ()

测长

复制代码
1
2
GByteArray->len

释放

复制代码
1
2
guint8 * g_byte_array_free ()

插入

复制代码
1
2
3
GByteArray * g_byte_array_append () GByteArray * g_byte_array_prepend ()

访问

复制代码
1
2
GByteArray->data[i]

移除

复制代码
1
2
3
4
GByteArray * g_byte_array_remove_index () GByteArray * g_byte_array_remove_index_fast () GByteArray * g_byte_array_remove_range ()

引用和解引用

复制代码
1
2
3
GByteArray * g_byte_array_ref () void g_byte_array_unref ()

排序

复制代码
1
2
3
void g_byte_array_sort () void g_byte_array_sort_with_data ()

GBytes字节

创建

复制代码
1
2
3
4
5
6
GBytes * g_bytes_new () GBytes * g_bytes_new_take () GBytes * g_bytes_new_static () GBytes * g_bytes_new_with_free_func () GBytes * g_bytes_new_from_bytes ()

访问

复制代码
1
2
3
gconstpointer g_bytes_get_data () gpointer g_bytes_unref_to_data ()

测长

复制代码
1
2
gsize g_bytes_get_size ()

引用和解引用

复制代码
1
2
3
GBytes * g_bytes_ref () void g_bytes_unref ()

hash

复制代码
1
2
guint g_bytes_hash ()

比较

复制代码
1
2
3
gboolean g_bytes_equal () gint g_bytes_compare ()

GByteArray和GBytes转换

复制代码
1
2
3
GBytes * g_byte_array_free_to_bytes () GByteArray * g_bytes_unref_to_array ()

函数功能说明及综合演示

GByteArray创建

复制代码
1
2
3
4
5
GByteArray * g_byte_array_new () GByteArray * g_byte_array_new_take () GByteArray * g_byte_array_sized_new () GByteArray * g_byte_array_set_size ()
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建一个字节数组 GByteArray * g_byte_array_new (void); // 创建字节数组,并填充为data指定的值。数组创建完后,其长度即为len GByteArray * g_byte_array_new_take (guint8 *data, gsize len); // 创建字节数组,并预分配内存空间。避免之后添加元素而多次内存申请或重新调整大小。注意此时字节数组的实际长度仍为0。 GByteArray * g_byte_array_sized_new (guint reserved_size); // 函数g_byte_array_new和g_byte_array_set_size组合使用等效于g_byte_array_sized_new GByteArray * g_byte_array_set_size (GByteArray *array, guint length);

GByteArray测长

字节数组也没有测长的函数,可以直接访问其成员变量len

复制代码
1
2
GByteArray->len

GByteArray释放

复制代码
1
2
guint8 * g_byte_array_free ()
复制代码
1
2
3
4
5
// 字节数组释放,如果free_segment设置为TRUE,其实际字节内容也会被释放。 guint8 * g_byte_array_free (GByteArray *array, gboolean free_segment);

GByteArray插入

复制代码
1
2
3
GByteArray * g_byte_array_append () GByteArray * g_byte_array_prepend ()
复制代码
1
2
3
4
5
6
7
8
9
10
// 字节数组只有头插和尾插两种操作,没有insert操作 GByteArray * g_byte_array_append (GByteArray *array, const guint8 *data, guint len); GByteArray * g_byte_array_prepend (GByteArray *array, const guint8 *data, guint len);

下面是以上功能的示例代码:
源码见glib_examplesglib_byte_arrayglib_byte_array_insert

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <glib.h> gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; guint i = 0; barr = g_byte_array_new(); g_byte_array_append(barr, (guint8 *)"World", 5); g_byte_array_prepend(barr, (guint8 *)"Hello", 5); g_print("barr:(len:%d)%s n", barr->len, barr->data); g_print("barr->data: n"); for(i=0; i<barr->len; i++) { g_print("%c ", barr->data[i]); } g_print("n"); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
4
[Invalid UTF-8] barr:(len:10)HelloWorldxef{xe2x7f barr->data: H e l l o W o r l d

可以看出,append和prepend添加的两个字符串,被拼在了一起,由于没有结尾符,打印出来有一部分会显示乱码。

字符数组可以存储任意值,这是普通动态数组和指针数组无法做到的。
在HelloWorld后面添加一个’’符号。
源码见glib_examplesglib_byte_arrayglib_byte_array_insert_end_zero

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <glib.h> gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; guint i = 0; barr = g_byte_array_new(); g_byte_array_append(barr, (guint8 *)"World", 5); g_byte_array_prepend(barr, (guint8 *)"Hello", 5); g_byte_array_append(barr, (guint8 *)"", 1); g_print("barr:(len:%d)%s n", barr->len, barr->data); g_print("barr->data: n"); for(i=0; i<barr->len; i++) { g_print("%c ", barr->data[i]); } g_print("n"); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
4
barr:(len:11)HelloWorld barr->data: H e l l o W o r l d

当然,’’可以添加到字节数组的任意位置。
源码见glib_examplesglib_byte_arrayglib_byte_array_insert_mid_zero

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <glib.h> gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; guint i = 0; barr = g_byte_array_new(); g_byte_array_append(barr, (guint8 *)"Hello", 5); g_byte_array_append(barr, (guint8 *)"", 1); g_byte_array_append(barr, (guint8 *)"World", 5); g_print("barr:(len:%d)%s n", barr->len, barr->data); g_print("barr->data: n"); for(i=0; i<barr->len; i++) { g_print("%c ", barr->data[i]); } g_print("n"); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
4
barr:(len:11)Hello barr->data: H e l l o W o r l d

此时虽然使用%s无法打印出来,但仍可以通过数组地址直接访问到对应的数据。

GByteArray访问

字节数组没有专门访问的函数,在上一节,我们也展示了如何访问字节数组的成员。
字节数组的每一个元素都是一个字节,我们可以根据地址直接访问它。

复制代码
1
2
barr->data[i];

注意,有些字符是非显示字符,尽管存在字节数组中,但无法通过%c打印出来,此时可通过%d打印。

GByteArray移除

复制代码
1
2
3
4
GByteArray * g_byte_array_remove_index () GByteArray * g_byte_array_remove_index_fast () GByteArray * g_byte_array_remove_range ()
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 根据数组下标移除数组元素,后面的数组元素会依次补上。 GByteArray * g_byte_array_remove_index (GByteArray *array, guint index_); // 根据数组下标移除数组元素,最后一个数组元素会补上此空缺。 GByteArray * g_byte_array_remove_index_fast (GByteArray *array, guint index_); // 根据数组下标和个数移除多个数组元素 GByteArray * g_byte_array_remove_range (GByteArray *array, guint index_, guint length);

字节数组移除示例:
源码见glib_examplesglib_byte_arrayglib_byte_array_remove

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <glib.h> static void _byte_array_print(GByteArray *barr, gconstpointer user_data) { guint i = 0; g_print("%s", (gchar *)user_data); for(i=0; i<barr->len; i++) { g_print("%c ", barr->data[i]); } g_print("n"); } gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; barr = g_byte_array_new(); g_byte_array_append(barr, (guint8 *)"Hello,World", strlen("Hello,World")); _byte_array_print(barr, "ori barr: "); g_byte_array_remove_index(barr, 5); _byte_array_print(barr, "remove_index(5) barr: "); g_byte_array_remove_index_fast(barr, 5); _byte_array_print(barr, "remove_index_fast(5) barr: "); g_byte_array_remove_range(barr, 5, 3); _byte_array_print(barr, "remove_range(5,3) barr: "); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
4
5
ori barr: H e l l o , W o r l d remove_index(5) barr: H e l l o W o r l d remove_index_fast(5) barr: H e l l o d o r l remove_range(5,3) barr: H e l l o l

GByteArray排序

复制代码
1
2
3
void g_byte_array_sort () void g_byte_array_sort_with_data ()
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
void g_byte_array_sort (GByteArray *array, GCompareFunc compare_func); 对字节数组进行排序,排序函数由用户指定。 void g_byte_array_sort_with_data (GByteArray *array, GCompareDataFunc compare_func, gpointer user_data); 与g_byte_array_sort功能相同,排序函数带用户自定义参数。 由于g_byte_array_sort和g_byte_array_sort_with_data功能完全一样,这里只演示g_byte_array_sort的使用方法。

示例代码如下:
源码见glib_examplesglib_byte_arrayglib_byte_array_sort

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <glib.h> static void _byte_array_print(GByteArray *barr, gconstpointer user_data) { guint i = 0; g_print("%s", (gchar *)user_data); for(i=0; i<barr->len; i++) { g_print("%c ", barr->data[i]); } g_print("n"); } static gint _byte_array_cmp_func(gconstpointer a, gconstpointer b) { //return (guint8 *)a - (guint8 *)b; // Caution: Wrong method! address, not value! return *(guint8 *)a - *(guint8 *)b; } gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; barr = g_byte_array_new(); g_byte_array_append(barr, (guint8 *)"Hello,World", strlen("Hello,World")); _byte_array_print(barr, "ori barr: "); g_byte_array_sort(barr, _byte_array_cmp_func); _byte_array_print(barr, "sorted barr: "); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
ori barr: H e l l o , W o r l d sorted barr: , H W d e l l l o o r

GBytes创建

复制代码
1
2
3
4
5
6
GBytes * g_bytes_new () GBytes * g_bytes_new_take () GBytes * g_bytes_new_static () GBytes * g_bytes_new_with_free_func () GBytes * g_bytes_new_from_bytes ()
复制代码
1
2
3
4
5
// 最简单的创建GBytes的方式。要注意,传入的data会被拷贝一份,至于如何释放,将在释放一节详细展开。 GBytes * g_bytes_new (gconstpointer data, gsize size);

GBytes访问

复制代码
1
2
3
gconstpointer g_bytes_get_data () gpointer g_bytes_unref_to_data ()

GBytes测长

复制代码
1
2
gsize g_bytes_get_size ()

GBytes引用和解引用

复制代码
1
2
3
4
// 当解引用时,如果GBytes对象不再有引用值,则GBytes会自动释放所有内存 GBytes * g_bytes_ref () void g_bytes_unref ()

以上函数的示例代码:
源码见glib_examplesglib_byte_arrayglib_bytes_basic

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; gsize size = 0; gconstpointer mem = NULL; bytes = g_bytes_new("abc", 3); size = g_bytes_get_size(bytes); mem = g_bytes_get_data(bytes, NULL); g_print("mem(len:%d):%s n", (gint)size, (gchar *)mem); g_bytes_unref(bytes); return 0; }

运行结果:

复制代码
1
2
mem(len:3):abc

使用valgrind工具检测一下是否有内存泄露。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# valgrind --tool=memcheck --leak-check=full ./glib_bytes_basic ==3588== Memcheck, a memory error detector ==3588== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==3588== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==3588== Command: ./glib_bytes_basic ==3588== ==3588== Invalid read of size 1 ==3588== at 0x518ACB3: vfprintf (vfprintf.c:1661) ==3588== by 0x524A384: __vasprintf_chk (vasprintf_chk.c:66) ==3588== by 0x4EC11EB: g_vasprintf (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0) ==3588== by 0x4E9CD3F: g_strdup_vprintf (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0) ==3588== by 0x4E87424: g_print (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0) ==3588== by 0x400964: main (glib_bytes_basic.c:15) ==3588== Address 0x5961043 is 0 bytes after a block of size 3 alloc'd ==3588== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3588== by 0x4E856D0: g_malloc (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0) ==3588== by 0x4E9CC17: g_memdup (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0) ==3588== by 0x4E5C434: g_bytes_new (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0) ==3588== by 0x400922: main (glib_bytes_basic.c:9) ==3588== mem(len:3):abc ==3588== ==3588== HEAP SUMMARY: ==3588== in use at exit: 2,214 bytes in 9 blocks ==3588== total heap usage: 19 allocs, 10 frees, 35,978 bytes allocated ==3588== ==3588== LEAK SUMMARY: ==3588== definitely lost: 0 bytes in 0 blocks ==3588== indirectly lost: 0 bytes in 0 blocks ==3588== possibly lost: 0 bytes in 0 blocks ==3588== still reachable: 2,214 bytes in 9 blocks ==3588== suppressed: 0 bytes in 0 blocks ==3588== Reachable blocks (those to which a pointer was found) are not shown. ==3588== To see them, rerun with: --leak-check=full --show-leak-kinds=all ==3588== ==3588== For counts of detected and suppressed errors, rerun with: -v ==3588== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

可以看到,有一处内存泄露。
通过查看调用栈,发现此处内存泄露是g_print导致,原因是GBytes里面只有3个字节,没有字符串常有的’’结束符,导致打印时内存访问越界。
我们将下面一行对内存的访问去掉,改为只打印GBytes字节的长度。
g_print("mem(len:%d):%s n", (gint)size, (gchar *)mem);
改为
g_print("mem len:%d n", (gint)size);
再次使用valgrind检查,无内存泄露。
可见,printf会导致内存访问越界。

GBytes引用和解引用

复制代码
1
2
3
4
// 前面已经讲过,unref用来解引用一个对象,当最后一个计数为0时,对象销毁。 GBytes * g_bytes_ref () void g_bytes_unref ()

GBytes hash

复制代码
1
2
3
// 在创建字节型hash表时作为参数传给g_hash_table_new guint g_bytes_hash ()

GBytes比较

复制代码
1
2
3
4
5
6
// 判断两个字节是否相等 // 比较两个字节大小 // 另外,b_bytes_equal也可以在创建字节hash表时作为参数传给g_hash_table_new gboolean g_bytes_equal () gint g_bytes_compare ()

字节比较举例如下:
源码见glib_examplesglib_byte_arrayglib_bytes_compare

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes1; GBytes *bytes2; gint ret = 0; gboolean equal = FALSE; bytes1 = g_bytes_new ("blah", 4); bytes2 = g_bytes_new ("blah", 4); ret = g_bytes_compare (bytes1, bytes2); equal = g_bytes_equal(bytes1, bytes2); g_print("ret:%d, equal:%s n", ret, equal ? "TRUE" : "FALSE"); g_bytes_unref (bytes2); bytes2 = g_bytes_new ("bla", 3); ret = g_bytes_compare (bytes1, bytes2); equal = g_bytes_equal(bytes1, bytes2); g_print("ret:%d, equal:%s n", ret, equal ? "TRUE" : "FALSE"); g_bytes_unref (bytes2); bytes2 = g_bytes_new ("abcd", 4); ret = g_bytes_compare (bytes1, bytes2); equal = g_bytes_equal(bytes1, bytes2); g_print("ret:%d, equal:%s n", ret, equal ? "TRUE" : "FALSE"); g_bytes_unref (bytes2); g_bytes_unref (bytes1); return 0; }

运行结果:

复制代码
1
2
3
4
ret:0, equal:TRUE ret:1, equal:FALSE ret:1, equal:FALSE

GByteArray和GBytes转换

复制代码
1
2
3
4
5
6
7
// g_byte_array_free_to_bytes 字节数组转换为字节 // g_bytes_unref_to_array 字节转换为字节数组 // g_byte_array_free_to_bytes 等价于 g_byte_array_free 加 g_bytes_new_take // g_bytes_unref_to_array 等价于 g_bytes_unref_to_data 加 g_byte_array_new_take GBytes * g_byte_array_free_to_bytes () GByteArray * g_bytes_unref_to_array ()

字节数组转换为字节
源码见glib_examplesglib_byte_arrayglib_byte_array_to_bytes

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <glib.h> gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; GBytes *bytes = NULL; gconstpointer data = NULL; gsize size = 0; barr = g_byte_array_new (); g_byte_array_append (barr, (guint8 *)"Hello", 6); bytes = g_byte_array_free_to_bytes (barr); data = g_bytes_get_data (bytes, &size); g_print("size:%d, data:%s n", (gint)size, (gchar *)data); g_bytes_unref (bytes); return 0; }

运行结果:

复制代码
1
2
size:6, data:Hello

字节转换为字节数组
源码见glib_examplesglib_byte_arrayglib_bytes_to_byte_array

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <glib.h> static const gchar *HELLO = "Hello"; static const gsize N_HELLO = 5; gint main(gint argc, gchar **argv) { gconstpointer memory; GByteArray *array; GBytes *bytes; gint ret = -1; bytes = g_bytes_new (HELLO, N_HELLO); memory = g_bytes_get_data (bytes, NULL); array = g_bytes_unref_to_array (bytes); ret = memcmp(array->data, (guint8 *)memory, array->len); g_print("ret:%d n", ret); ret = memcmp(array->data, (guint8 *)HELLO, N_HELLO); g_print("ret:%d n", ret); g_byte_array_unref (array); return 0; }

运行结果:

复制代码
1
2
3
ret:0 ret:0

专题

GByteArray数据结构的内存模型

之前的例子,都是把常量字符串添加到字节数组中,下面演示把局部变量及堆内存添加到字节数组的效果。

局部变量添加到字节数组中
示例代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <glib.h> static void _byte_array_append(GByteArray *barr) { gchar str0[8] = {0}; gchar str1[8] = {0}; gchar str2[8] = {0}; gchar str3[8] = {0}; g_strlcpy(str0, "Hello", 8); g_strlcpy(str1, ",", 8); g_strlcpy(str2, "World", 8); g_strlcpy(str3, "", 8); g_byte_array_append(barr, (guint8 *)str0, 5); g_byte_array_append(barr, (guint8 *)str1, 1); g_byte_array_append(barr, (guint8 *)str2, 5); g_byte_array_append(barr, (guint8 *)str3, 1); g_print("barr(in-func):(len:%d)%s n", barr->len, barr->data); } gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; guint i = 0; barr = g_byte_array_new(); _byte_array_append(barr); g_print("barr(out-func):(len:%d)%s n", barr->len, barr->data); g_print("barr->data: n"); for(i=0; i<barr->len; i++) { g_print("%c ", barr->data[i]); } g_print("n"); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
4
5
barr(in-func):(len:12)Hello,World barr(out-func):(len:12)Hello,World barr->data: H e l l o , W o r l d

堆上申请的内存
示例代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <glib.h> gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; guint i = 0; gchar *str[4] = {NULL}; str[0] = g_strdup("Hello"); str[1] = g_strdup(","); str[2] = g_strdup("World"); str[3] = g_strdup(""); barr = g_byte_array_new(); g_byte_array_append(barr, (guint8 *)str[0], 5); g_byte_array_append(barr, (guint8 *)str[1], 1); g_byte_array_append(barr, (guint8 *)str[2], 5); g_byte_array_append(barr, (guint8 *)str[3], 1); memset(str[0], 0, strlen(str[0])); memset(str[1], 0, strlen(str[1])); memset(str[2], 0, strlen(str[2])); memset(str[3], 0, strlen(str[3])); g_print("barr:(len:%d)%s n", barr->len, barr->data); g_print("barr->data: n"); for(i=0; i<barr->len; i++) { g_print("%c ", barr->data[i]); } g_print("n"); g_free(str[0]); g_free(str[1]); g_free(str[2]); g_free(str[3]); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
4
barr:(len:12)Hello,World barr->data: H e l l o , W o r l d

这说明字节数组拥有自己的内存空间,并不像指针数组那样,指针数组元素本身有自己的内存空间,但其指向的内存并不属于指针数组。

把字节数组中各元素的地址打印出来:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <glib.h> gint main(gint argc, gchar **argv) { GByteArray *barr = NULL; guint i = 0; gchar *str[4] = {NULL}; str[0] = g_strdup("Hello"); str[1] = g_strdup(","); str[2] = g_strdup("World"); str[3] = g_strdup(""); barr = g_byte_array_new(); g_byte_array_append(barr, (guint8 *)str[0], 5); g_byte_array_append(barr, (guint8 *)str[1], 1); g_byte_array_append(barr, (guint8 *)str[2], 5); g_byte_array_append(barr, (guint8 *)str[3], 1); g_print("barr:(len:%d)%s n", barr->len, barr->data); for(i=0; i<barr->len; i++) { g_print("barr->data[%d](addr:%p):%c n", i, &barr->data[i], barr->data[i]); } g_print("nlen=%d(addr:%p)n", barr->len, &barr->len); g_free(str[0]); g_free(str[1]); g_free(str[2]); g_free(str[3]); g_byte_array_free(barr, TRUE); return 0; }

运行结果:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
barr:(len:12)Hello,World barr->data[0](addr:0x102de50):H barr->data[1](addr:0x102de51):e barr->data[2](addr:0x102de52):l barr->data[3](addr:0x102de53):l barr->data[4](addr:0x102de54):o barr->data[5](addr:0x102de55):, barr->data[6](addr:0x102de56):W barr->data[7](addr:0x102de57):o barr->data[8](addr:0x102de58):r barr->data[9](addr:0x102de59):l barr->data[10](addr:0x102de5a):d barr->data[11](addr:0x102de5b): len=12(addr:0x102e008)

可见,字节数组的内存空间模型如下:
请将下面三行逐行复制到文本编辑器并调整字体为等宽字体如宋体、Courier New等再查看。

复制代码
1
2
3
4
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬┈┬───┐ └H┴e┴l┴l┴o┴,┴W┴o┴r┴l┴d┴0┤..│len│ └┈┴───┘

这里需要注意的是,data和len的内存地址并不是连续的。

GBytes字节的释放

GBytes没有像普通数组、指针数组及字节数组类似的g_xxx_free()释放函数。

有以下几种释放GBytes字节内存的方法。
g_bytes_new + g_bytes_unref

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; bytes = g_bytes_new("abc", 3); g_bytes_unref(bytes); return 0; }

g_bytes_new + g_bytes_unref_to_data
其中,g_bytes_unref_to_data = g_bytes_get_data + g_bytes_unref

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; gpointer data = NULL; gsize size = 0; bytes = g_bytes_new("abc", 3); data = g_bytes_unref_to_data(bytes, &size); g_free(data); return 0; }

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; gpointer data = NULL; gsize size = 0; gchar *str = g_strdup("abc"); bytes = g_bytes_new(str, 3); g_free(str); data = g_bytes_unref_to_data(bytes, &size); g_free(data); return 0; }

g_bytes_new_take+g_bytes_unref
g_bytes_new_take会将传入的内存据为己有,其他人不能再修改该内存。
当GBytes最后一个引用被解除后,会自动调用g_free函数释放该内存空间。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; gchar *str = g_strdup("abc"); bytes = g_bytes_new_take(str, 3); g_bytes_unref(bytes); // g_free(str) // Caution: can not free here! return 0; }

注意:以下代码会导致段错误,原因是g_bytes_new_take的第一个参数要求的必须是堆上分配的内存。官方文档如下。

Because of this data must have been created by a call to g_malloc(), g_malloc0() or g_realloc()
or by one of the many functions that wrap these calls (such as g_new(), g_strdup(), etc)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; bytes = g_bytes_new_take("abc", 3); g_bytes_unref(bytes); return 0; }

g_bytes_new_static+g_bytes_unref
常量字符串无法使用g_bytes_new_take创建字节结构,但g_bytes_new_static可以创建。
g_bytes_new_static传入的第一个参数可以是一个常量字符串或者地址不被修改的字符串。
尽管官方文档特意指明不被修改或释放(data must be static (ie: never modified or freed)),但在实际例子中仍可以证明,字符串的值可以被修改,甚至可以被释放,当然,释放之后,就无法获取到值了。尽管如此,当使用的是一个堆上的内存时,最好在unref之后再对其进行释放。

常量字符串

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; bytes = g_bytes_new_static("abc", 3); g_bytes_unref(bytes); return 0; }

或者

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; const char *str = NULL; str = "abc"; bytes = g_bytes_new_static(str, 3); g_bytes_unref(bytes); return 0; }

地址不被修改的字符串
(这里演示当内存被释放时,通过g_bytes_get_data无法获取到该值)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <glib.h> gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; gchar *str = NULL; gsize size = 0; gconstpointer data = NULL; str = g_strdup("abc"); bytes = g_bytes_new_static(str, 4); data = g_bytes_get_data(bytes, &size); g_print("data(ori):%s n", (const gchar *)data); g_strup(str); data = g_bytes_get_data(bytes, &size); g_print("data(strup):%s n", (const gchar *)data); g_free(str); data = g_bytes_get_data(bytes, &size); g_print("data(after free):%s n", (const gchar *)data); g_bytes_unref(bytes); return 0; }

上述代码运行结果:

复制代码
1
2
3
4
data(ori):abc data(strup):ABC [Invalid UTF-8] data(after free):x80xb2Gx01

g_bytes_new_with_free_func+g_bytes_unref

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <glib.h> static void _bytes_free_func(gpointer data) { if(NULL != data) { g_print("free data: %s n", (gchar *)data); g_free(data); } } gint main(gint argc, gchar **argv) { GBytes *bytes = NULL; gchar *str = NULL; gsize size = 0; gconstpointer data = NULL; str = g_strdup("abc"); bytes = g_bytes_new_with_free_func(str, 4, _bytes_free_func, str); data = g_bytes_get_data(bytes, &size); g_print("data:%s n", (const gchar *)data); g_bytes_unref(bytes); return 0; }

运行结果:

复制代码
1
2
3
data:abc free data: abc

最后

以上就是怕孤独季节最近收集整理的关于4_05_GLib库入门与实践_字节数组的全部内容,更多相关4_05_GLib库入门与实践_字节数组内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(69)

评论列表共有 0 条评论

立即
投稿
返回
顶部