Is glib usable in an unobtrusive way?
Asked Answered
B

3

9

I was looking for a good general-purpose library for C on top of the standard C library, and have seen several suggestions to use glib. How 'obtrusive' is it in your code? To explain what I mean by obtrusiveness, the first thing I noticed in the reference manual is the basic types section, thinking to myself, "what, am I going to start using gint, gchar, and gprefixing geverything gin gmy gcode gnow?"

More generally, can you use it only locally without other functions or files in your code having to be aware of its use? Does it force certain assumptions on your code, or constraints on your compilation/linking process? Does it take up a lot of memory in runtime for global data structures? etc.

Boyle answered 3/7, 2013 at 12:20 Comment(2)
Could the close warriors please go back to trolling wikipedia for articles to delete rather than interfering with SO? This question is perfectly answerable, and there are plenty of reasonable ways to interpret "unobtrustive" such that the question has objective answers.Divide
Voting to reopen, we have plenty of C expertise on SO to answer a question like this with expertise rather than opinion, as evidenced by the extant answers.Squires
D
7

The most obtrustive thing about glib is that any program or library using it is non-robust against resource exhaustion. It unconditionally calls abort when malloc fails and there's nothing you can do to fix this, as the entire library is designed around the concept that their internal allocation function g_malloc "can't fail"

As for the ugly "g" types, you definitely don't need any casts. The types are 100% equivalent to the standard types, and are basically just cruft from the early (mis)design of glib. Unfortunately the glib developers lack much understanding of C, as evidenced by this FAQ:

Why use g_print, g_malloc, g_strdup and fellow glib functions?

"Regarding g_malloc(), g_free() and siblings, these functions are much safer than their libc equivalents. For example, g_free() just returns if called with NULL.

(Source: https://developer.gnome.org/gtk-faq/stable/x908.html)

FYI, free(NULL) is perfectly valid C, and does the exact same thing: it just returns.

Divide answered 3/7, 2013 at 12:39 Comment(10)
Really? That's quite terrible. Would dynamically replacing abort() with something else help me? ... (or maybe I should think of doing those kinds of things.)Boyle
No, because the code in glib is not prepared to get a NULL return value. The interface contract of g_malloc is that it never returns without succeeding, and the only way to meet this contract is by terminating the program if it doesn't succeed. In principle you could catch SIGABRT and longjmp out, but then you would leave the objects that were in the process of being manipulated in an indeterminate state, so any further access to them would be potentially dangerous.Divide
So, glib is out of the question then. Thanks :-(Boyle
+1 for shattering my assumption that glib was written by C experts.Squires
Yes. It's rather ironic that glib was originally designed as part of GIMP, which is just about the worst-possible program to have abort when malloc fails, and one where malloc is very likely to fail due to allocation of huge resources...Divide
I really like glib (and GTK+), but this part is unfortunate. It's even more strange that it's only mentioned indirectly in the documentation for e.g. g_try_malloc() which does not abort.Afterward
The idea behind g_malloc() aborting on allocation failure is because nobody can realistically write, test and maintain code which behaves correctly in the face of allocation failure. In many (but not all) cases, the only thing you’re going to do if an allocation fails is to gracefully close the program. OSs have provided large virtual address spaces for many years now. We might as well use them, and not spend time writing error handling code for malloc() failure which we can’t reasonably test. If you do need to write software which handles malloc() failure, don’t use GLib. And good luck.Stope
“The types are 100% equivalent to the standard types” — not 100% true: they abstract some platform differences, typically around the width of long int/long long int. Since C99, however, the provision of standard types in libc has become a lot better, so the g-prefixed types are indeed now largely irrelevant. “Unfortunately the glib developers lack much understanding of C” — that’s not very nice. Bear in mind that GLib is 21 years old, and the C language (and platforms it runs on) have changed a lot since then. GLib has only broken API once in that 21 years.Stope
@PhilipWithnall: I've addressed the fallacy about malloc failure many, many times in other more relevant places; I'm not going to do it in the comments again. Even if the application is going to terminate, a library must offer it the capability to do so in a way that doesn't induce data loss. The OP already indicated that this is a show-stopping problem for their usage case, so your assertion that it's not a problem is counterfactual to the situation at hand that my answer was addressing.Divide
It’s not a fallacy. It’s a use case choice. The entire GNOME desktop, and a large amount of other software functions well for hundreds of thousands of users despite using g_malloc(). You appear to place lots of value on handling all allocation failures. Others place less value on that. It’s valid to bring this up, but it’s one of the less important considerations about whether to use GLib. Other, probably more relevant considerations, are: what other libraries is your app using, and what dependencies do they bring in? Do you need support for bindings? Can you use something other than C?Stope
H
2

I have used GLib professionally for over 6 years, and have nothing but praise for it. It is very light-weight, with lots of great utilities like lists, hashtables, rand-functions, io-libraries, threads/mutexes/conditionals and even GObject. All done in a portable way. In fact, we have compiled the same GLib-code on Windows, OSX, Linux, Solaris, iOS, Android and Arm-Linux without any hiccups on the GLib side.

In terms of obtrusiveness, I have definitely "bought into the g", and there is no doubt in my mind that this has been extremely beneficial in producing stable, portable code at great speed. Maybe specially when it comes to writing advanced tests.

And if g_malloc don't suit your purpose, simply use malloc instead, which of course goes for all of it.

Humoresque answered 4/7, 2013 at 9:36 Comment(7)
What about @R.'s claim in his [answer here]((https://mcmap.net/q/356739/-is-glib-usable-in-an-unobtrusive-way), that glib, when malloc'ing on its own, assumes the allocation is successful and aborts when that is not the case?Boyle
Also, as for "buying into the g", do you mean glib-oriented style necessitated by whoever is using your code, or just the fact that you use the library a lot yourself? If it's the former, then this is a problem for me, as I work in a group and am limited in what I can change in others' code.Boyle
It is correct that g_malloc will issue a g_error if the alloc fails, which is considered fatal (calling abort) in the default implementation. So if you work on code where malloc failing is not fatal, than you should use malloc and free instead of g_malloc and g_free. I guess what I mean is that to really reap the benefits of platform-independent code you should go "all in", so if you choose to use some GLib but your codebase does not use it extensively, you can not expect the codebase itself to be platform independent.Humoresque
@HavardGraff: All of the glib functions internally use g_malloc to obtain memory. It doesn't matter if you abstain from using g_malloc directly; as long as you're using any function in glib that needs to allocate memory, it will call g_malloc, and then you're screwed.Divide
@R: Most of the internals uses the slice-allocator which is superior to malloc in most cases. And there is no universal truth to being "screwed" by calling abort when out of memory, it is a choice of implementation and opinions / requirements differs from writing hyper-defensive code to "fail early". Calling abort when out of memory is a contract you can choose to accept or not, and if you accept it, GLib is an excellent choice. (Saying GLib developers lacks knowledge of C is a very rude and flippant comment, not cool)Humoresque
@HavardGraff: If calling various glib functions can abort() my process, then I am screwed. I need to write (among other things) apps or daemons which don't crash, period. And a general-purpose library cannot take the liberty of crashing the process.Boyle
@einpoklum: well, best of luck not crashing (or being killed by the OS) if you run out of memory. And of course a general-purpose library can call abort; GLib is, and it does.Humoresque
A
1

Of course you can "forget about it elsewhere", unless of course those other places somehow interact with glib code, then there's a connection (and, arguable, you're not really "elsewhere").

You don't have to use the types that are just regular types with a prepended g (gchar, gint and so on); they're guaranteed to be the same as char, int and so on. You never need to cast to/from gint for instance.

I think the intention is that application code should never use gint, it's just included so that the glib code can be more consistent.

Afterward answered 3/7, 2013 at 12:24 Comment(1)
Typesdefs are included, because glib was created before stdint.h was there. So it's because of legacy: https://mcmap.net/q/209294/-why-does-everybody-typedef-over-standard-c-typesBret

© 2022 - 2024 — McMap. All rights reserved.