GLib is a lower-level library that provides many useful definitions and functions, portable across different Architectures and Operating Systems:
Links:
All the GLib basic types are included with the main header:
#include <glib.h>
| GLib Type | Corresponding Type in C |
|---|---|
| gchar | char |
| guchar | unsigned char |
| gint | int |
| guint | unsigned int |
| gshort | short |
| gushort | unsigned short |
| glong | long |
| gulong | unsigned long |
| gfloat | float |
| gdouble | double |
| gint8 | int, 8 bits wide |
| guint8 | unsigned int, 8 bits wide |
| gint16 | int, 16 bits wide |
| guint16 | unsigned int, 16 bits wide |
| gint32 | int, 32 bits wide |
| guint32 | unsigned int, 32 bits wide |
| gint64 | int, 64 bits wide |
| guint64 | unsigned int, 64 bits wide |
| gpointer | void *, untyped pointer |
| gconstpointer | const void *, constant untyped pointer |
| gboolean | Boolean value, either TRUE or FALSE |
The advantage of these functions over those in the standard C library is the built-in error handling. If a problem occurs during runtime, g_error() can step in to examine it.
| GLib Function | Corresponding C Function |
|---|---|
| gpointer g_malloc(gulong n_bytes) | void *malloc(size_t size) with error handling |
| gpointer g_malloc0(gulong n_bytes) | like malloc(), but initializes memory as in calloc() |
| gpointer g_try_malloc(gulong n_bytes) | like malloc() without error checking |
| gpointer g_realloc(gpointer mem, gulong n_bytes) | void *realloc(void *ptr, size_t size) with error checking |
| gpointer g_try_realloc(gpointer mem, gulong n_bytes) | realloc() without error checking |
| void g_free(gpointer mem) | void free(void *ptr) |
It is also provided a useful macro to allocate a desired number of data structures:
g_new(struct_type, n_structs)
C library
my_data = (dummy_data_type*) malloc(sizeof(dummy_data_type) * DATA_LENGTH); if (my_data == NULL) { fprintf(stderr, "Couldn't allocate memory\n"); exit(EXIT_FAILURE); // Should be called a system wide error handling routine. }
GLib library
my_data = g_new(dummy_data_type, DATA_LENGTH);
GLib has utility functions to handle two types of strings:
gchar strings can be passed as argument to all the string.h functions. Additionally, GLib provide the following functions:
GString is a data type containing a pointer to the memory area containing the string chars, the length of the string and the length of the area of memory allocated for the string:
typedef struct _GString GString; struct _GString { gchar *str; gsize len; gsize allocated_len; };GLib provides the following functions:
GLib uses four runtime error logging functions, in order of the priority levels:
| Functions | Level | Meaning |
|---|---|---|
| g_message() | G_LOG_LEVEL_MESSAGE | for informative messages indicating normal runtime behavior |
| g_warning() | G_LOG_LEVEL_WARNING | for warnings or problems that won't cause errant operation (at least not yet) |
| g_critical() | G_LOG_LEVEL_CRITICAL | for warnings that likely are going to matter |
| g_error() | for fatal errors; calling this function terminates your program |
This utilities take parameters like printf() (a format string followed by a list of substitution parameters). There's no need to put a '\n' at the end of the format, though.
To add a signature (compile time) of the application to the log messages, it has to be used the G_LOG_DOMAIN macro.
#undef G_LOG_DOMAIN #define G_LOG_DOMAIN "GLibTest" [...] g_message("Info message"); g_warning("Warning message"); g_critical("Critical message"); g_error("Error message");
GLibTest-Message: Info message (process:18977): GLibTest-WARNING **: Warning message (process:18977): GLibTest-CRITICAL **: Critical message GLibTest-ERROR **: Error message aborting...
In the default configuration, g_error is fatal. The function g_log_set_always_fatal can set other logging level as fatal, ie to set all warnings and critical messages as fatal:
g_log_set_always_fatal(G_LOG_LEVEL_WARNING|G_LOG_LEVEL_CRITICAL)
To facilitate an uniform logging through all the library there are also two wrapper functions to the classical print functions:
g_print() g_printerr()
All these functions have ways to set different handlers.
g_log_set_handler() g_set_print_handler() g_set_printerr_handler()
The prototype of a log handler function is:
void (*GLogFunc)(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data);
The Gtimer is nothing more than a stopwatch that is as accurate as your system clock. Here is a demonstration:
#include <glib.h> #define DURATION 200000 int main(int argc, char **argv) { GTimer *clock = NULL; gint i; gdouble elapsed_time; gulong us; /* microseconds */ clock = g_timer_new(); g_timer_start(clock); g_print("Timer started.\n"); g_print("Loop started.. "); /* wasting CPU time like this is only allowed in programming examples */ for (i = 0; i < DURATION; i++) { ; } g_print("and finished.\n"); g_timer_stop(clock); g_print("Timer stopped.\n"); elapsed_time = g_timer_elapsed(clock, &us); g_print("Elapsed: %g s\n", elapsed_time); g_print(" %ld us\n", us); g_timer_destroy(clock); return 0; }
Main Loop with context
GMainContext* context = NULL; GMainLoop* loop = NULL; context = g_main_context_new(); loop = g_main_loop_new(context, FALSE); timeout_add_to_context(1000, periodic_one, NULL, context); g_main_loop_run(loop);
Timeout on a generic context
guint timeout_add_to_context(guint interval, GSourceFunc func, gpointer data, GMainContext *context) { GSource *source; guint id; g_return_val_if_fail(func != NULL, 0); source = g_timeout_source_new(interval); g_source_set_callback(source, func, data, NULL); id = g_source_attach(source, context); g_source_unref(source); return id; }
Thread init
GThread *thread = NULL; GError *err = NULL; g_thread_init(NULL); thread = g_thread_create(thread, NULL, TRUE, &err);
Mutex
static GStaticMutex mutex = G_STATIC_MUTEX_INIT; g_static_mutex_lock(&mutex); /* ... */ g_static_mutex_unlock(&mutex);
Add a watch to a file descriptor
GIOChannel* channel; channel = g_io_channel_unix_new(file_descriptor); io_add_watch_to_context(channel, (G_IO_IN|G_IO_IN), io_handler, data);
Watch on a generic context
guint io_add_watch_to_context(GIOChannel *channel, GIOCondition condition, GSourceFunc func, gpointer data, GMainContext *context) { GSource *source; guint id; g_return_val_if_fail(channel != NULL, 0); g_return_val_if_fail(func != NULL, 0); source = g_io_create_watch(channel, condition); g_source_set_callback(source, func, data, NULL); id = g_source_attach(source, context); g_source_unref(source); return id; }
# C Compiler settings CC=gcc CC_FLAGS=-O2 -g -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations # Header files needed by the compiler CC_INCLUDES=-I. \ -pthread \ -I/usr/include/glib-2.0 \ -I/usr/lib/glib-2.0/include # Libraries needed by the linker LD_LIBS=-pthread \ -L/usr/lib \ -Wl,-rpath,/usr/lib \ -lglib-2.0 # Project Files MODULES=./main.o # Target executable file TARGET=exec all: $(TARGET) clean: rm -f $(TARGET) $(MODULES) $(TARGET): $(MODULES) $(CC) $(CC_INCLUDES) $(CC_FLAGS) -o $@ $(MODULES) $(LD_LIBS) %.o: %.c $(CC) $(CC_INCLUDES) $(CC_FLAGS) -c -o $*.o $<