Why use GLib functions?
Asked Answered
N

7

31

While programming in C and GTK+, why is it "better" to use g_strdup_printf, g_free, g_strcmp0 etc... and fellow GLib functions?

Nonesuch answered 10/2, 2010 at 20:34 Comment(2)
I changed the "glibc" tag to "glib". Mind that those two are completely different things - glibc is the GNU C Library that's used (unless some other implementation is used) to compile executables on Linux so they can use syscalls and standard functions. glib is the higher-level set of utility functions that came out of the GTK project long ago.Aerophone
Avoid using glib. You'll end up with 10,000 lines of bad code compiled into your project to get something trivial like a linked list - a very expensive and abstract one, of course - which requires you include most of the rest of the glib lib as this mess is horrifically intertwined.Beesley
S
36

In general, GLib's purpose is a utility and portability library. Those in itself are reasons to consider using it.

The specific functions you mention all offer something extra on top of their C standard library variants:

  • g_strdup_printf is like sprintf, but actually allocates the buffer for you and saves you the guesswork of how large the buffer should be. (The return value should be g_free'd.)
  • g_free is like free, but checks for a NULL-pointer.
  • g_strcmp0 is like strcmp, but treats a NULL-pointer like an empty string, and thus sorts it in front.
Strophic answered 10/2, 2010 at 20:48 Comment(10)
The standard free is defined to be a no-op if passed a NULL-pointer, so g_free offers no bonus there.Millionaire
Still a good idea to match g_malloc() with g_free() instead of free() from libc. I have observed that on Windows it's possible for multiple DLLs to link to separate versions of malloc() (with separate internal heap structures) and mixing-and-matching causes crashes. Not sure if this is a real world concern or if it might be true on other platforms, but by using GLIB's wrappers you can avoid that.Notwithstanding
My advice to anyone considering using Gnome is to use C++ for the STL. You can write "classless C++" - straight C using the STL. Works great. The amount of scope creep in the Gnome project is just ridiculous. They really think they're smarter than the people who wrote C, and they try to "fix" the language at every turn. It doesn't need fixing.Corking
@Corking It's really reaching to say 'they think they're smarter than the people who wrote C' when in reality they just chose to use an open language in a particular way that they liked and that suited their purposes. You don't have to agree with their usage or preferences, but don't spin an absurd yarn about them being derogatory to the language or its architects. I also think C++ is totally orthogonal to this, but hey.Byrdie
@Chris Lutz: some implementations in the wild will faill on free(NULL) (I saw this myself on an embedded project). The C standard is one thing, real world necessities is another. Here's someone who saw it on another platform too: https://mcmap.net/q/75926/-does-free-ptr-where-ptr-is-null-corrupt-memory . That's what GLib is for: real-world portability.Diplomatics
@liberforce, if you're working with a compiler that's so bad free(NULL) fails you'll have much bigger problems as any such compiler would have to be hideously bad to fail in such a way and will likely produce more bugs than usable code. Find a better environment. In the meantime do what any pro would do, wrap such functions and provide useful error messages in the wrapper code.Beesley
It fails at runtime, not at compile time, so not the compiler fault. The "find a better environment" is laughable when you're on big projects with fixed delivery dates. About your "the one that do what I do are noobs" argument, that's at best, childish.Diplomatics
Your explanation for g_strcmp0 is slightly off. It is true that the function handles NULL strings, but it does not treat them the same as empty strings. In other words, g_strcmp0 (NULL, "") will not return 0, but -1Glossary
@Diplomatics Is it really that hard for implementations to include a built in NULL check for free()?Ticklish
@user16217248: You're missing the point. It's not hard, it's just that it makes use of toolchains inconsistent. The GLib, by providing alternatives that abstract these hétérogeneous implementations, gives you something that behaves the same way everytime, everywhere. You can then just consider these problems solved and focus on the real work you have to do.Diplomatics
E
8

For consistent behavior in multiple operating systems. It's a portability thing.

In some other unix environments other than Linux, or if your program is compiled on windows, some of those functions may not exist or behave differently on the target operating system.

Using the glib versions ensure consistent behavior.

Equinox answered 10/2, 2010 at 20:49 Comment(2)
C89 all by itself is the most standard language in the World. Which would you rather debug for platform differences, C89, or C89 wrapped in some now-obscure Gnome wrapper? Yeah, me too.Corking
No, it isn't. Visual Studio doesn't support it (#146881). Also, C99 and C89 are pretty limited—for most non-trivial projects you'll need at least some functions from POSIX/Windows API (think dlopen, threads, sockets, atomics, memory mapped files, ...), so you're going to want some sort of portability layer.Soler
D
5

The GLib provides portability and basic stuff you'd expect nowadays from any programming language, like collection types (linked lists, arrays, hash tables, etc.). Here are some of the benefits GLib can give you.

Portability


The point of the GLib is to be portable not to the C standard, but to the implementations of the standard. The GLib takes care of the known quirks that might seem useless at first sight until you need to port your code to a platform that has those nasty bugs.

Let's take the example of g_free, as many criticize it. There are platforms where free(NULL) will fail, even if C99 says it should work. That check exists since at least 1998 (I tracked it in git history). Some may say it's not needed anymore, but even in 2017 I worked at a company that checks for NULL before calling free because otherwise it would crash on their embedded platform. It also serves as a wrapper for intrumentation of your code when you want to do some serious memory debugging.

Readability


It helps improving the readability of your code by providing some wrapper functions that not only improve portabitlity, but also help you avoid many language pitfalls. How many of you test malloc to see if it returns NULL? How many of you have a way to recover if it returns NULL, since you're basicly out of memory?

g_malloc will abort the application if it can't allocate what you want, and in many applications, this is just the behavior you want. For very big allocations that may fail, you have g_try_malloc. That is the same as malloc but still gives you the benefit of being a wrapper that may be used for instrumentation.

Being able to write:

char *buffer = g_malloc(30);
/* Do something with it ... */
g_free (buffer);

...frees the mind and lets the developer focus on the task she's trying to achieve. It also avoids having your program crash much later because it's trying to write using NULL pointer and you have to track down the allocation.

The standard C library is full of traps, and not having to micro manage every single line of code you write is a relief. Just read the BUGS section of the manpages for some functions and youo'll see. Having less boilerplate code to check for errors makes the code simpler to read, which improves the maintainability, and causes less bugs.

Features


Another point is the whole bunch of collection types GLib provides and that you don't have to reimplement. Just because reimplementing a linked list is easy doesn't mean you should do it. I worked at another company that shipped code with several linked list implementations, because some developpers would just have the Not Invented Here syndrome and would redevelop their own. A common, thouroughly tested, widespread library like GLib helps avoiding this nonsense. You shouldn't redevelop that stuff unless you have very specific performance constraints.

Diplomatics answered 14/12, 2017 at 11:45 Comment(1)
Anybody who does naked free() is a noobie at best. Nobody claiming to be a professional C programmer is going to do that. NIH is a problem, but the solution isn't using someone else's black bock, it's using functions and modular code. Beyond that, GLib's version of many things, and the linked list in particular, are very abstract, but also very expensive and prone to memory leaks. Having the user allocate the memory for each link's storage, as well as the API hitting malloc() for each link might be OK if storing blobs, but if the link sizes are known a lot of complexity in the service of zilchBeesley
O
4

Their behavior is well-defined on any platform that GTK+ supports, as opposed to the native functions which may perhaps sometimes partway work.

Ocarina answered 10/2, 2010 at 20:48 Comment(4)
In my experience C is more reliable than Gnome. Of course, in many cases, if you dig through Gnome code deeply enough, the Gnome function is just a #define of a standard C function. BTW, the BEST way to know how a function works on linux/Unix platforms is to use the man pages.Beesley
"C" is not a library though, and what "libc" supports can vary from platform to platform.Ocarina
If it makes you feel better to research the capabilities of every platform you use and lift code from other projects rather than learn about a cross-platform toolkit then I won't stop you.Ocarina
Or, more like, said native functions may simply not exist, or at least will be implemented in radically different ways that would otherwise lead to an endless nightmare of macros. Then there's all the polyfills for extremely vintage C89 (which IMO was admirable but is ever less relevant; at this point, it may be more enablement than help). Newer G* versions will start requiring C99 anyway by the looks of it - finally!Byrdie
B
3

I have to say, this is well intended but not well executed. It is sorta nice that your program won't crash and burn when you try to free() a pointer more than once. Or sort a NULL string. But that's a mixed blessing. It prevents you from discovering these nasty bugs in your code as well. Not only will you have a hard time getting your program ported some day, because you're relying on non-standard functions, you'll have a really hard time because your code was buggy and you never found out.

Bimetallism answered 10/2, 2010 at 21:24 Comment(12)
The standard says that free(NULL) (or any free on a null pointer) is perfectly safe and is a no-op. No benefits there.Millionaire
Must agree with Hans here. I'm taking over some legacy code, and it's clear to me that 4 successive crews of C programmers have been intimidated enough of all the changes that will have to be made to bring this into standard C 89 that they punted and left a huge mess. I'm just thrilled, for example, that the linked-list implementation from Gnome I'm going to have to rewrite from scratch, OR, if I can swing it, convert this code to C++ so I can use the STL. BTW, plain old vanilla C with the STL works fine, except for anonymous structures - which C++ brain-farted.Corking
@user2548100, can you provide a resource with more info on the "anonymous structure problem" in C++?Vellicate
@Corking "plain old vanilla C with the STL" is one of the most hilariously bad contradictions in terms I've ever heardByrdie
“Not only will you have a hard time getting your program ported some day, because you're relying on non-standard functions” is false. Part of the point of GLib is to ease porting between platforms — it provides wrapper APIs around a number of seemingly-standard functions purely because their behaviour does differ between platforms, and GLib abstracts those differences.Interinsurance
Some programmers do pay attention to the license terms.Bimetallism
@underscore_d, You've lead a very sheltered life!Beesley
@PhilipWithnall, Some code will never get ported, and you are assured of that going in. Also, if you're on Linux and working on a back-end app, there aren't many other places to go, now are there? Cost and capability make that proposition very unlikely. I've ported most of my code over the last 25 yrs, and for the few advantages Gnome alleges, it's not worth the time, cost and attention span. I'd much rather take the time to revisit some of my own code, or some written by another talented programmer than use a black box written by an army of hubris.Beesley
@RocketRoy At least you make your biases clear... as well as your lack of attention to detail, which discredits them. GNOME is a desktop. GLib is one of the libraries it uses. And you've just written off the thousands of people who ever contributed to either as "an army of hubris" and, worse, mutually exclusive with being "another talented programmer" such as, presumably, yourself. At least we know there's no point trying to have an actual discussion here (but for a slanging match, this is the place to be).Byrdie
@RocketRoy: There are valid reasons to, or to not, use GLib, depending on what aims you are trying to achieve when writing code (portability, ease of development, access to a large number of projects which use GLib, etc.). Couching your arguments in abuse and hyperbole is not helpful to anyone (me, you, or anyone trying to read this thread and get advice from it). I hope you can move on from whatever trauma you’ve had with GLib in the past and remove some of the hate from your life. I’m done here. :-)Interinsurance
@PhilipWithnall, My initial reaction was to the insidious way everything calls stuff from many other modules. Then I started actually reading the code. I never saw anything creative or inspiring, but saw some really inefficient code that only existed to make use of some other piece of Gnome code. I also did enough research to find extended discussions on the tradeoffs that were made in C's string lib, and was convinced that the people who set the C Standard got it right, and the Gnome people just didn't think about the issues very much.Beesley
@RocketRoy "Imagine what they could have achieved if they hadn't wasted their time on GLib." They probably might have wasted time using some other library written by another "army of hubris". Even the most accomplished developers may not have self-written libraries for all data structures they will ever need. Say, for an application prototype, we may not want to spend time implementing a full blown hash table. I'm not a fan of glib but it does save me numerous hours(and headache) while prototyping. And for that, I do appreciate and thank the community that develops glib.Estellestella
C
-1

10 years ago, using the Gnome lib may have made sense, but its now a legacy liability. C89 is arguably the most standard language in the world, with very stable features and syntax, so debugging someone else's C89 code is doable.

By contrast Gnome's glib changes it's function's features outside of the C Standard, so not only do you get to deal with debugging obscure wrapper code made of C, but your code may stop working because Gnome changes it's wrapper functions.

Exhibit A: g_snprintf()

A safer form of the standard sprintf() function. The output is guaranteed to not exceed n characters (including the terminating nul character), so it is easy to ensure that a buffer overflow cannot occur.

See also g_strdup_printf().

In versions of GLib prior to 1.2.3, this function may return -1 if the output was truncated, and the truncated string may not be nul-terminated. In versions prior to 1.3.12, this function returns the length of the output string.

The return value of g_snprintf() conforms to the snprintf() function as standardized in ISO C99. Note that this is different from traditional snprintf(), which returns the length of the output string.

The format string may contain positional parameters, as specified in the Single Unix Specification.

I'm less than thrilled I get to write (yet another) linked-list to replace Gnome's, AND yet another version of snprintf() and a bunch of crappy wrapper code that silently malloc()s memory, thereby breaking the one absolute maxium of C coding: "Always malloc() and free() in the same scope" to replace g_strdup_printf().

g_strdup_printf ()

Similar to the standard C sprintf() function but safer, since it calculates the maximum space required and allocates memory to hold the result. The returned string should be freed with g_free() when no longer needed.

Add to this the thrill of making massive numbers of string changes in the code to do "useful" things like change gchar to char, gint to int, gboolean to bool, etc, etc, etc, ad nauseam until my Subversion comparisons are now a phone book. Worse, you end up having to change more and more code because this stuff is littered all over the .h files, so it keeps expanding, like a boated corpse, into a huge mess.

If you're scoping a contract job and see glib.h anywhere, RUN!!! Just say NO!.

PS: Downloading the source, removing all the Gnome-specific types, and recompiling it to make your own "g_"-less functions sorta, kinda works, and is a big time-saver.

Exhibit B: g_strdup_printf()

More horrific Gnome crappola from Gnome. Gnome has lots of "lovely" functions like g_strdup_vprintf() that "magically" know how much storage you need to hold your returned string, and I had occasion to look behind the "magic". This wins my award for the most hideous abuse of C ever.

If you keep tracing g_strdup_vprintf() back through all the wrapper functions, you come to this gem in gmessages.c....

/**
 * g_printf_string_upper_bound:
 * @format: the format string. See the printf() documentation
 * @args: the parameters to be inserted into the format string
 *
 * Calculates the maximum space needed to store the output
 * of the sprintf() function.
 *
 * Returns: the maximum space needed to store the formatted string
 */
gsize
g_printf_string_upper_bound (const gchar *format,
                             va_list      args)
{
  gchar c;
  return _g_vsnprintf (&c, 1, format, args) + 1;
}

Not only is ANY printf() function slower than snot at absolute zero, you'll notice they allocate an entire byte, yup, a whole gchar c, for storage, which guarantees overflow, but then who cares? they get the length of the string they'll need to malloc() - because they are going to turn around and do the whole printf() over again - this time, "magically" with just enough storage.

They'll add +1 to the size, of course, so you'll have room for a nul-terminator, guaranteed, at horrific expense of course, but they've hid it so deep in the code they're betting you'll just give up and use it blindly and not notice what a massive brain-fart this is. Gee, thanks guys. I just love my code to crawl.

Don't let the _g_vsnprintf() function throw you off, because in gprintfint.h you'll discover that little gem is just another name for plain old vanilla vsnprintf();

/* GLIB - Library of useful routines for C programming
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GLib Team and others 2002.  See the AUTHORS
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 */

#ifndef __G_PRINTFINT_H__
#define __G_PRINTFINT_H__

#ifdef HAVE_GOOD_PRINTF

#define _g_printf    printf
#define _g_fprintf   fprintf
#define _g_sprintf   sprintf
#define _g_snprintf  snprintf

#define _g_vprintf   vprintf
#define _g_vfprintf  vfprintf
#define _g_vsprintf  vsprintf
#define _g_vsnprintf vsnprintf

#else

#include "gnulib/printf.h"

#define _g_printf    _g_gnulib_printf
#define _g_fprintf   _g_gnulib_fprintf
#define _g_sprintf   _g_gnulib_sprintf
#define _g_snprintf  _g_gnulib_snprintf

#define _g_vprintf   _g_gnulib_vprintf
#define _g_vfprintf  _g_gnulib_vfprintf
#define _g_vsprintf  _g_gnulib_vsprintf
#define _g_vsnprintf _g_gnulib_vsnprintf

#endif

#endif /* __G_PRINTF_H__ */

It's highly recommended that you watch the Wizard Of Oz again before working with Gnome, so you'll know not to look behind the curtain. Welcome to my nightmare!

Anyone that thinks Gnome is more stable than C is badly lacking in critical thinking. You trade performance and transparency for a few nice things that are done better in the STL.

Corking answered 29/1, 2014 at 18:20 Comment(9)
"Always malloc() and free() in the same scope" made me laugh. Seriously, in real world applications, you react to events, allocate memory on some, destroy that memory in response to other events. GLib documents who is responsible for freeing the memory, who takes ownership of it, and that's what you want.Diplomatics
BTW, gboolean predates the C99 bool type. GLib started around 1996. The reasons for gboolean being gint are here: git.gnome.org/browse/glib/tree/ChangeLog.pre-1-2#n2532Diplomatics
You show _g_vsnprintf definitions but completely dismiss the hole #ifdef HAVE_GOOD_PRINTF which show that this has been done for portability. I could debunk all the other statements, but seeing that you're too lazy to just run git blame to see why some code appeared before complaining, I won't be the one who will do your homework.Diplomatics
This is just a poorly written screed, using objections most of which apply to any library above whatever you consider the acceptable baseline (C89 or POSIX). There's no sense in which "its now a legacy liability" as it remains actively developed & continually accrues modern features. Differences are documented, "legacy" features are optional & removed all the time (aside from innocuous ones like the, admittedly now silly, g typedefs), & so on. Debunking this is not a worthwhile task when simply reading some modern code using GLib would do that for you - but of course you don't want that...Byrdie
@underscore_d, Some poor soul at the Glib project should have read this before starting its design. The biggest problem with GLib is its hideous degree of coupling. Just off the charts. ehrscience.com/2012/11/12/…Beesley
@liberforce. So I now have to read all kinds of documentation to use your black box, and probably dig through the code and find all the places where you do "blind" malloc()s? That's white box, not black. I write apps, not libraries and I don't make people read thousands of lines of code to find where I malloc()ed memory that they missed and thus failed to free(). I make it obvious. If you aren't you're writing bad code.Beesley
@RocketRoy You make it obvious, right. And that's what GLib does. The ownership of the memory is documented, and that is what is used to generate the bindings for GLib, GTK+... You don't need to "guess".Diplomatics
@RocketRoy About GLib maintainers that started it in 1996 that should have read, before designing it, an article from 2012... I suppose they forgot their crystal ball to read in the future.Diplomatics
...one absolute maxium of C coding: "Always malloc() and free() in the same scope... I'm not sure which 'scope' you had in mind and neither do I know of any source which claims this as "one absolute maxium of C coding" nor the meaning of "maxium". Nevertheless, +1 for looking behind the curtain.Estellestella
R
-3

Here is an update. It looks the developer's realized their mistake:

g_mem_is_system_malloc has been deprecated since version 2.46 and should not be used in newly-written code.

GLib always uses the system malloc, so this function always returns TRUE.

Checks whether the allocator used by g_malloc() is the system's malloc implementation. If it returns TRUE memory allocated with malloc() can be used interchangeable with memory allocated using g_malloc(). This function is useful for avoiding an extra copy of allocated memory returned by a non-GLib-based API.

https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#g-mem-is-system-malloc

Readiness answered 24/11, 2015 at 12:12 Comment(3)
The removal of GLib’s malloc vtable is more complex than just a ‘mistake’. It was removed because the need for ctor support was deemed more important than the memory profiling feature which the vtable enabled; and in the meantime, libc’s support profiling support matured significantly. See bugzilla.gnome.org/show_bug.cgi?id=751592.Interinsurance
@PhilipWithnall What I meant was that adding it in the first place was a mistake. Removing it was not. Rather a good thing.Readiness
At the time (although I was not around, so this is based on a bit of archaeology and what I’ve heard), I believe adding it made sense; the support for profiling memory allocations using other methods and tools was poor at the time. GLib has been around (and API stable) for a long time.Interinsurance

© 2022 - 2024 — McMap. All rights reserved.