If you've been programming in C for any decent amount of time, it's inevitable that you'll end up with a bunch of "copy-paste" functions laying around somewhere in your disk. libz1 is basically my attempt at taking those copy-paste functions and turning them into a set of single header libraries.
While I have been programming in C for a decent bit now (maybe around an year)
and have contributed to a bunch of libraries I hadn't yet written a library of
my own. So now having written libz1
, I'd like to share some of my experience.
As it turns out, writing a library is actually rather easy. The difficult part
is designing it... and writing the documentation. Also keep in mind that
libz1
barely had any design decision involved since most of the functions were
fairly self-contained.
As of writing this post, libz1
contains the following libraries:
On a long enough timeline, the chances of a C programmer writing his own string library approaches 100.
Yup, I had to do it. But the good news is that unlike a lot of other string libraries which invent their own string type, zstr is designed to work with the good ol standard nul-terminated strings.
One of the goal of zstr was to complement the C standard string library instead of reinventing it. It contains a bunch of nice functions which aren't standardized, such as: find and replace characters within a string, search for a character case insensitively, find an arbitrary sized element from an array etc.
It also contains compatibility replacements for various useful, but non-standard
functions such as memmem
, mempcpy
, strcasestr
etc.
One thing which became somewhat of a pain was the fact that these compatibility functions had to be fast. It makes no sense to use wrappers if they're 10x slower than the system-libc ones.
Making these functions fast, in itself isn't too difficult of a task. What made
it difficult was the fact that zstr
is a single header library. Which means
that there's no room for doing optimizations which rely on undefined behavior
since the library will be build on environments on which I don't have much
control over.
Regardless, the end result is quite decent. A lot of the functions compete fairly well against Glibc, which is one of the faster libcs out there.
I do plan on adding some other functions to this library, but for now I've only included functions which I'm confident in.
zvec is a fairly straight-forward implementation of a type-safe dynamic array. The twist here is the fact that unlike most other vector implementation I've come across, this one is small-buffer optimized.
Small buffer optimization means avoid doing dynamic allocation for small inputs.
This is quite useful when you're expecting you're typical case to be small
enough to avoid having to malloc
, but at the same time you'd like to be able
to deal with edge-cases where dynamic allocation is necessary.
Unlike zstr
this library is pretty much complete. I don't see myself adding
anything else to it.
The C type system is rather primitive and lacks fine grained expressiveness. A lot of errors which could've been caught at compile time goes unnoticed due to it.
Compiler attributes somewhat solves this. But if you use compiler attributes, then you're making your source code less portable since attributes aren't standard (yet). C23 does standardize the attribute syntax which should make things better. However C23 isn't even finalized yet, and it's going to take a while until it gets widespread adoption.
zattr basically is a bunch of macros which allow you to portably use compiler attributes with a focus on improving compiler warnings, static analysis and runtime performance.
It includes various attributes which improve compiler warnings and static
analysis such as format
, noreturn
, returns_nonnull
etc.
Some of the attributes for improving performance such as hot
, cold
, pure
etc are included as well. It also includes some built-in such as
__builtin_expect
wrapped in linux style likely/unlikely
macros.
One of the focus of this library is that the absence or presence of an attribute
SHOULD NOT change the program behavior. As such, attributes such as aligned
or
cleanup
are not included.
There are some more attributes which I plan on adding to the library in the future given that they fit within the project's goal.
While this turned out to be far more work than I originally anticipated, it also turned out quite fun. And making a library instead of just having things as "copy-paste" functions forced me to think a lot harder about edge-cases and revealed some bugs as well.
There are a couple more libraries which I plan on adding. Some things I have on mind are a misc POSIX utility library, a tightly-packed linked list, a simple stack-based allocator, and a couple other things which I won't name now.
If implementing these turn out to be interesting, then I'll probably write a blog post about it. Otherwise if you'd still like to get updated then thankfully for you, CodeBerg recently updated their Gitea version which now supports RSS feed which you can subscribe to ;)
Tags: [ c ]