GString: A Revelation
As anybody who has ever developed in a modern object-oriented or scripting language and then learned C can tell you, working with strings in C sucks. It sucks really hard. Let me list some of the ways that C strings are terrible:
- Strings are bare char arrays in C; they require manual memory management
- As pointers, C strings are allocated on the heap. Unless they are string literals, in which case they are magical immutable things. Don’t you dare attempt to free() a string literal
- There is no way to test if a char array is a heap-allocated pointer or a string literal
- C strings have to be null terminated, or nothing works
- There is no reliable way to tell the length of a C string; strlen() will give incorrect results if the string isn’t null terminated.
- Copying a C string requires you to have allocated a char array greater than or equal to the size of the string to be copied. However, strlen() returns the size required, -1
- String concatenation requires the management of 2 pointers
- Most C string functions have “n” versions, that you should use instead of the base versions if you don’t want your program to be hacked
I’m sure there are others, but it’s late. The point here is that dealing with C strings is kind of a drag. Unfortunately for us, this comes with the territory; losing the baggage of object orientation also requires us to lose its conveniences. Or so I thought…
GString To The Rescue
While looking through the reference manual for GLib, I noticed a section: Strings. You read that right, GStrings are a thing! GLib provides a string class that does all the usual sorts of things you’d expect of a proper string object. Let’s talk about a few of them.
This is your string constructor. The documentation says that it “Creates a new GString, initialized with the given string.” You’ll notice that it doesn’t say who is responsible for the original char * when the string instantiation is complete. In search of the truth, I turned to Google.
Shockingly, Google proves unhelpful. After poking around, I decide to just look in the source code. Under the covers,
g_string_new calls out to
g_string_append_len, which in turn calls out to
g_string_insert_len. G_string_insert_len does some pointer jimmying, then finally calls memcpy to copy the contents of the char array into the string. The verdict: the GString does not take ownership of your char array; make sure you free it (if it’s not a string literal, of course) when you’re done with it.
This is your string destructor. This function takes two arguments: the string to free, and a gboolean. The gboolean is important; if you set it TRUE, it will free the underlying char array inside the GString. If you set it FALSE, then you are on the hook for its memory management. This is useful you want to return the char array from a function and you don’t need the GString object any more.
g_string_append and friends
GString provides a suite of string concatenation functions. You can append at the front or the end of a GString. The best part is that you don’t even have to worry about resizing the array; GString does all that for you!
g_string_printf and friends
GString provides several printf functions that function pretty much how you’d expect: they facilitate writing formatted strings into a GString using the semantics of printf. This allows you to convert non-string types to strings, and format your data. For us Java types, this is your FooType.toString() method replacement.
GString has three public fields: str, len, and allocated_len. Str is a pointer to the underlying C string. If you need to access the actual data of a GString, just call
the_string->str. Len is the length of the string. This would be equivilent to a call to
strlen(), but it is not dependent on a terminating null character. In fact, a GString can have null characters throughout without issue! Finally, allocated_len is the actual allocated size of str.
Consequences Were Never The Same
GString solves many of the issues of C Strings:
- GStrings encapsulate your C Strings; no longer are you subject to the tyranny of malloc
- If a function returns a GString, you need not worry if it is a heap allocated pointer or a string literal
- GStrings don’t need to be null terminated
- Testing the length of a GString is a simple matter of checking its
- Copying a GString is a simple call to
- String concatenation is a simple method call requiring no math
In a world with GStrings, string management in C became just a bit more tolerable. Object-oriented refugees worldwide give their heartfelt thanks to the brave men and women who gave us the GString.