Glib编程

                                          Glib 编程

  

 

     GLib是GTK+和GNOME工程的基础底层核心程序库,是一个综合用途的实用的轻量级的C程序库,它提供C语言的常用的数据结构的定义、相关的处理函数,有趣而实用的宏,可移植的封装和一些运行时机能,如事件循环、线程、动态调用、对象系统等的API。它能够在类UNIX的操作系统平台(如LINUX, HP-UNIX等),WINDOWS,OS2和BeOS等操作系统台上运行。
GLib需要一个支持线程的操作系统和一个字符集间转换函数iconv的支持,事实上大多现代的操作系统都有以上两项功能。
GLib由基础类型、对核心应用的支持、实用功能、数据类型和对象系统五个部分组成的。
GLib的最新版本是GLib2.2.1,可以到www.gtk.org网站下载其源代码。使用GLib2.0编写的应用程序,在编译时应该在编译命令中加入`pkg-config -cflags -libs glib-2.0`,如编译一个名为hello.c的程序,输出名为hello的可执行文件,则命令为:
gcc `pkg-config -cflags -libs glib-2.0` hello.c -o hello

在GLIB中将线程(gthread),插件(gmoudle)和对象系统(gobject)这三个子系统区别对待,编译时要注意加入相应的参数。

如程序中用到对象系统,编译时就应加入:
`pkg-config --cflags --libs gobject-2.0`

用到线程,编译时则加入:
`pkg-config --cflags --libs gthread-2.0`
用到插件,编译时则加入:
`pkg-config --cflags --libs gmoudle-2.0`

基础类型

GLib的基础是由基础类型、范围限定宏、标准宏、类型转换宏、字节次序变换宏、数学常数定义和杂项宏等各项组成的。这里主要介绍基础类型,因为它们遍及与GLIB相关的各种程序库和软件包中,如GTK+,GNOME,MONO等大的开源项目。

基础类型又称标准类型,GLib将C语言中的数据类型统一封装成自己的数据类型,均以小写字母'g'开头,如:gpointer是指针类型(void *)、guint是无符号整型(unsigned int)等,其中有一些是修饰性的,如:gint、gchar等,它们和C语言中的int、char是完全相同的。这些数据类型使用起来和C语言中的数据类型完全一样,当你熟悉了以后会发现它们的使用方法更灵活,更直观也更易于理解一些。当然你可以把C语言中的数据类型直接拿来使用,这丝毫不影响你编写程序的编译。
另外范围限定宏和类型转换宏也较常用,如G_MAXINT表示最大的int型值,用宏GINT_TO_POINTER(i)将整型变量i转换为指针型,宏GPOINTER_TO_INT(p)将指针型变量p转换为整型。
逻辑类型gboolean的值TRUE和FALSE是在常数宏中定义的,另外还包括G_E表示自然对数,G_PI表示圆周率,G_PI_2表示圆周率的1/2等一些数学常数。

对核心应用的支持

GLib对核心应用的支持包括事件循环、内存操作、线程操作、动态链接库的操作和出错处理与日志等。
下面代码演示了事件循环、内存操作、线程这三种功能的简单应用:

#include <glib.h>
static GMutex *mutex = NULL;
static gboolean t1_end = FALSE;
static gboolean t2_end = FALSE;
typedef struct _Arg Arg;
struct _Arg
{
GMainLoop* loop;
gint max;
};
void run_1(Arg *arg)
{
int i ;

for(i=0; i<arg->max; i++)
{
if(g_mutex_trylock(mutex) == FALSE)
{
//g_print("%d : thread 2 locked the mutex /n", i);
g_print("%d :线程2锁定了互斥对象/n", i);
g_mutex_unlock(mutex);
}
else
{
g_usleep(10);
}
}
t1_end = TRUE;
}
void run_2(Arg *arg)
{
int i;
for(i=0; i<arg->max; i++)
{
if(g_mutex_trylock(mutex) == FALSE)
{
//g_print("%d : thread 1 locked mutex /n", i);
g_print("%d :线程1锁定了互斥对象/n", i);
g_mutex_unlock(mutex);
}
else
{
g_usleep(10);
}
}
t2_end = TRUE;
}
void run_3(Arg *arg)
{
for(;;)
{
if(t1_end && t2_end)
{
g_main_loop_quit(arg->loop);
break;
}
}
}
int main(int argc, char *argv[])
{
GMainLoop *mloop;
Arg *arg;

if(!g_thread_supported())
g_thread_init(NULL);
mloop = g_main_loop_new(NULL, FALSE);

arg = g_new(Arg, 1);
arg->loop = mloop;
arg->max = 11;

mutex = g_mutex_new();
g_thread_create(run_1, arg, TRUE, NULL);
g_thread_create(run_2, arg, TRUE, NULL);
g_thread_create(run_3, arg, TRUE, NULL);

g_main_loop_run(mloop);
g_print("线程3退出事件循环/n");
g_mutex_free(mutex);
g_print("释放互斥对象/n");
g_free(arg);
g_print("释放参数所用的内存/n");
}

Makefile文件如下:
CC = gcc
all:
$(CC) `pkg-config --cflags --libs glib-2.0 gthread-2.0` loop.c -o loop
下面为输出结果:

0 :线程1锁定了互斥对象
1 :线程2锁定了互斥对象
2 :线程1锁定了互斥对象
3 :线程2锁定了互斥对象
4 :线程1锁定了互斥对象
5 :线程2锁定了互斥对象
6 :线程1锁定了互斥对象
7 :线程2锁定了互斥对象
8 :线程1锁定了互斥对象
9 :线程2锁定了互斥对象
10 :线程1锁定了互斥对象
线程3退出事件循环
释放互斥对象
释放参数所用的内存

以上例程创建了三个线程,其中run_1和run_2操作互斥对象,run_3检索前两个线程是否结束,如结束的话,则执行g_main_loop_quit退出事件循环。由于线程的运行是不确定的,所以不一定每次都是这一输出结果。

首先定义一个结构类型来保存创建的事件循环的对象指针和线程运行时的最多循环次数,一般情况下,如果为此数据结构来分配内存的话,用 Arg *arg = (Arg *)malloc(sizeof(Arg));,释放时用free(arg);,这种传统的做法曾经让很多C语言的初学者头痛,尤其是需要多次操作的时候,GLib中提供了类似的函数g_malloc和g_free,最好用的方法是其将g_malloc函数封装成了宏g_new,这个宏有两个参数,第一个是结构类型,第二个是要分配结构的数量,这段代码中只用到了一个Arg数据结构,所以是g_new(Arg, 1)。在程序结束时用g_free来释放。

在线程初始化时,首先是判断线程是否初始化的函数g_thread_supported,如果其返回FALSE则表明线程并未初始化,这时必须用g_thread_init来初始化,这是较明智的做法。

事件循环GMainLoop在用g_main_loop_new创建之后并不马上运行,用g_main_loop_run运行后,还要用g_main_loop_quit退出,否则循环将一直运行下去,这两个函数的参数都是GMainLoop型的指针,在主函数中并未直接运行 g_main_loop_quit,而是把它放在线程的函数中了,这一点需读者注意。

实用功能

GLib中包含了近二十种实用功能,从简单的字符处理到初学者很难理解的XML解析功能,这里介绍两种较简单的:随机数和计时。

下面代码演示如何产生1-100之间的随机整数和演示如何计算30000000次累加在计算时用的时间:

/* until.c 用来测试实用功能 */
#include <glib.h>
int main(int argc, char *argv[])
{
GRand *rand;
GTimer *timer;

gint n;
gint i, j;
gint x = 0;
rand = g_rand_new(); //创建随机数对象
for(n=0; n<20; n++)
{ //产生随机数并显示出来
g_print("%d/t",g_rand_int_range(rand,1,100));
}
g_print("/n");
g_rand_free(rand); //释放随机数对象
//创建计时器
timer = g_timer_new();
g_timer_start(timer);//开始计时
for(i=0; i<10000; i++)
for(j=0; j<3000; j++)
x++;//累计
g_timer_stop(timer);//计时结束
//输出计时结果
g_print("%ld/tall:%.2f seconds was used!/n",x,g_timer_elapsed(timer,NULL));
}
Makefile文件内容如下:
CC = gcc all: $(CC) `pkg-config --cflags --libs glib-2.0 ` until.c -o until

输出结果:
48 95 95 99 90 24 90 29 78 4 53 87 1 86 7 93 57 88 75 4
30000000 all:1.47 seconds was used!

GLIB中的每个对象几乎都有一个或多个*_new函数来创建,计时器GTimer和随机器GRand也一样,也都有相对应的函数来结束对象的使用,如GTimer的g_timer_stop和GRand的g_rand_free。

这可能是GLIB实用功能中最简单的两种了,许多朋友会一目了然。我们还应注意到GLIB的代码风格和封装技巧是具有独到之处的,这种风格和技巧足以让一些自称简洁实用的SDK汗颜,学习掌握这一风格可能会让我们受益匪浅。

数据类型

GLib中定义了十几种常用的数据结构类型和它们的相关操作函数,下面是关于字符串类型的简单示例:
#include <glib.h>
int main(int argc, char *argv[])
{
GString *s;
s = g_string_new("Hello");
g_print("%s/n", s->str);
s = g_string_append(s," World!");
g_print("%s/n",s->str);
s = g_string_erase(s,0,6);
g_print("%s/n",s->str);
s = g_string_prepend(s,"Also a ");
g_print("%s/n",s->str);

s = g_string_insert(s,6," Nice");
g_print("%s/n",s->str);
}

Makefile文件如下:
     CC = gcc
all:
    $(CC) `pkg-config --cflags --libs glib-2.0 ` string.c -o str
   

下面是输出结果:

Hello
Hello World!
World!
Also a World!
Also a Nice World!

字符串在编程中出现频率之高,即使是初学者也很清楚,追加、删除和插入等常用操作理解后,还可以进一步了解掌握其它更复杂的操作。

GLib提供了一种内存块(GMemChunk)数据类型,它为分配等大的内存区提供了一种非常好用的操作方式,下面程序演示了内存块数据类型的简单用法:
#include <glib.h>
int main(int argc, char *argv[])
{
GMemChunk *chunk; //定义内存块
gchar *mem[10]; //定义指向原子的指针数组
gint i, j;
//创建内存块
chunk = g_mem_chunk_new("Test MemChunk", 5, 50, G_ALLOC_AND_FREE);
//名称,原子的长度, 内存块的长度,类型
for(i=0; i<10; i++)
{
//创建对象
//mem[i] = g_chunk_new(gchar, chunk);
mem[i] = (gchar*)g_mem_chunk_alloc(chunk);
for(j=0; j<5; j++)
{
mem[i][j] = 'A' + j;//为内存块中的指针赋值
}
}

g_mem_chunk_print(chunk); //显示内存块信息
for(i=0; i<10; i++)
{
g_print("%s/t",mem[i]);//显示内存块中的内容
}

for(i=0; i<10; i++)
{
g_mem_chunk_free(chunk,mem[i]); //释放所有分配的内存
}
g_mem_chunk_destroy(chunk);
}
Makefile文件件如下:

CC = gcc
all:
    $(CC) `pkg-config --cflags --libs glib-2.0` data1.c -o data1
   

以下为输出结果:

GLib-INFO: Test MemChunk: 80 bytes using 2 mem areas
ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE

这里说明这一数据类型的原因是通过它可以他细体会内存分配这一运行时处理环节的应用之妙。
我们在程序中分配的是50字节的空间,而实际用的是80字节,由此可以看出其在分配内存时本身用到了部分内存空间。

从上面的示例代码中可以看出,在GLib中几乎所有的对象都是C语言的结构类型,一般命名以大写字母G开头的单词,如GList表示双向链表,所有与之相关的操作函数都以小写的字母g加下划线加小写的单词加下划线开头,如以g_list_*开头的函数都是与这相关的操作函数,而且这些函数中的第一个参数多数是此对象的指针。

GLIB中的数据类型在GLIB本身,尤其是GTK+中频繁用到,了解掌握这些数据类据类型的用法是非常必要的,这对进一步灵活开发GTK+程序来说是关键一环,而且是对大学中的《数据结构》一科的很好回顾。

时间: 2024-10-01 06:14:56

Glib编程的相关文章

浅谈Windows系统下C语言编程中Glib库的使用_C 语言

在这个C的变成世界里,有许多实用的库,其中最有名的且最通用(跨多个平台的实现包括Windows,要知道很多实用的编程库都不提供Windows的实现)就是GLib这个库,其中就有实现线程的部分. glib库是Linux平台下最常用的C语言函数库,它具有很好的可移植性和实用性. glib是Gtk +库和Gnome的基础.glib可以在多个平台下使用,比如Linux.Unix.Windows等.glib为许多标准的.常用的C语言结构提供了相应的替代物. 如果在程序中要使用到glib库中的函数,则应该包

Gtk2-Perl Glib 1.242发布 编程工具

GTK2-Perl是一个用于GTK++ 2.x和各种相关库的Perl绑定的集合名称.这些模块易于编写GTK+ 和GNOME应用程序,通过使用natural.Perlish和面向对象的语法. Gtk2-Perl Glib 1.242该版本变更了在GPL许可声明的地址,修复了一个在Glib::GenPod的默认pspec值的排版,并删除了重复在glib%basic_types:GenPod. 软件信息:http://gtk2-perl.sourceforge.net/ 下载地址:http://sou

【整理】libc、glibc和glib的关系

[glibc 和 libc]  glibc 和 libc 都是 Linux 下的 C 函数库. libc 是 Linux 下的 ANSI C 函数库:glibc 是 Linux 下的 GUN C 函数库.  ANSI C 和 GNU C 有什么区别呢?         ANSI C 函数库是基本的 C 语言函数库,包含了 C 语言最基本的库函数.这个库可以根据头文件划分为 15 个部分,其中包括:  <ctype.h>:包含用来测试某个特征字符的函数的函数原型,以及用来转换大小写字母的函数原型

在Python中封装GObject模块进行图形化程序编程的教程_python

Python 是用于编码图形界面的极佳语言.由于可以迅速地编写工作代码并且不需要费时的编译周期, 所以可以立即使界面启动和运行起来,并且不久便可使用这些界面. 将这一点与 Python 易于链接本机库的能力结合起来,就可以形成一个出色的环境. gnome-python 是为 Python 封装 GNOME 及其相关库的软件包. 这使您能够用 Python 编写外观与核心 GNOME 应用程序完全相同的应用程序,而所花的时间只是用 C 编写该应用程序所花的一部分. 然而,不用 C 进行编程会有一个

python网络编程之数据传输UDP实例分析

  本文实例讲述了python网络编程之数据传输UDP实现方法.分享给大家供大家参考.具体分析如下: 一.问题: 你觉得网络上像msn,qq之类的工具在多台机器之间互相传输数据神秘吗?你也想玩一下在两台机器之间传数据吗?今天让python告诉我们基本原理吧,当然只是做简单的了解,实际情况复杂的多. 我们今天用python实现一个简单的udp程序. 二.程序实现: 1) 使用模块 (socket)套接字模块: 套接字模块是一个非常简单的基于对象的接口,它提供对低层BSD套接字样式网络的访问 .使用

python网络编程之文件下载实例分析

  本文实例讲述了python网络编程之文件下载实现方法.分享给大家供大家参考.具体如下: 真是越看越喜欢python啊,想要了解它提供的http和ftp下载功能,原来是如此的简单. 1.相应模块 ftplib模块定义了FTP类和一些方法,用以进行客户端的ftp编程.我们可用python编写一个自已的ftp客户端程序,用于下载文件或镜像站点.如果想了解ftp协议的详细内容,请参考RFC959或是查看python帮助吧. Urllib模块提供了非常高级的接口来从网络上抓取数据,主要使用到的是url

asp编程中的测试打印、有效性检查及错误处理

编程|错误|错误处理|打印 经常看到一些初学asp的朋友为了测试一个值到处用response.write来打印, 而要看页面效果时再删除这些语句或加上注释,在正式版本出来以前要如此反复 多次.而有些人为了减少麻烦,干脆全当它是正确的,不做测试输出,像这样极 易出现各种各样的问题,最常见的是如果要生成一条sql语句,需要使用变量,如 果不做测试打印,很难做到一次正确,在chinaasp论坛里经常见到这种问题,老 是有人问这条语句为什么会出错等问题,实际上他只要打印出这条语句看一下语 法是否正确就行

求助贴:c语言编程问题

问题描述 求助贴:c语言编程问题 解决方案 在你的程序里scanf()函数返回的是一个正整数,无论你输入的是不是-1,他接收的一直是一个参数,所以返回的一直是1.并且还是使用"%lu"来接收参数的,输入-1一定不会退出程序的,输入1.2scanf()只接收到了1,因为1.2不符合输入的规则"%lu",也会返回1.程序不会停下 解决方案二: 疑惑:1.输入0有效,输出真确2.输入-1不退出,-1被强制转换为int类型3.输入1.2输出1个奇数后又printf();然后

面向服务编程

    从最初的面向过程编程,到后来觉得难以理解的面向对象编程,从软件工程的发展历程中来看,这已经成为我们编程路上熟知的两种编程方式.     接触了ITOO项目这么长时间,才发现,不知不觉,我们已经进入了软件工程发展历程之面向服务编程的开发.本篇博客的主题便是面向服务编程.     [一.面向服务编程从何而来?]     想要了解面向服务编程的发展方向以及它在软件行业中所占的地位,我们首先要了解的便是它的起源和发展.没有任何一种方法是一蹴而就的,应该是经历了数十年渐进的演化历程.下面,我们就来