Atomic Object’s blog on everything we find fascinating.

Nicer C99 APIs with Designated Initializers

While working on a library for property-based testing in C, I discovered a trick that can be used to make significantly nicer library interfaces in C99: “designated initializers”. As of C99, struct literals can have their fields set by name, in any order. The C99 standard explicitly updated the behavior for how fields in struct literals are handled:

6.7.8 point 21:

“If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.” (emphasis mine)

Since memory with static storage duration is already initialized to zero, this means that in C99 we can finally depend on stack-allocated structs’ fields being set to zero, rather than garbage data from previous stack frames. This is a huge improvement! If pointers to structs are used as arguments for function calls, it also gives C99 a portable way of using optional and keyword arguments.

socket99 for BSD sockets

With this in mind, I made a wrapper for a particularly awkward library: the BSD sockets API. Its designers had to make a generic interface that could configure any kind of network connection, anticipating future networks’ needs. What they came up with is several functions, a subset of which need to be called in the right order, depending on the use case. Many of these take parameters cast to a generic socket struct type. (A union couldn’t be used, because it would need to know all possible types, and new ones are still being added.) There are a lot of details to get right when using them, and while checking for errors at every step along the way is crucial, it also makes relatively basic networking code quite verbose.

For many common use cases, only a little information is necessary. My library (socket99) takes a struct with a few keyword arguments set, and writes the result to an output struct — either a file descriptor, or details about the error. The library can make client or server connections on TCP, UDP, or Unix domain sockets (in either stream or datagram mode).

Also, libraries using structs like this are still statically typed, so if the fields change between library versions, breaking changes will lead to errors at compile time rather than settings being silently ignored.