Cool C Tricks

C often feels limited in what it can express. It doesn’t have cool higher level features like first class functions and pattern matching. But C, as simple as it is, still has some very useful syntactic tricks and features that not many people know.

Designated Initializers

Many people are aware of the ability to statically initialize arrays like so:

int fibs[] = {1, 1, 2, 3, 5};

C99 actually supports a more expressive way to statically initialize all different kinds of aggregate data types (structs, unions, and arrays).

Arrays

We can designate the elements of an array to initialize. This is particularly useful if we need to keep a mapping up-to-date with respect to a set of #defines. Consider a set of error defines, like:

/* Entries may not correspond to actual numbers. Some entries omitted. */
#define EINVAL 1
#define ENOMEM 2
#define EFAULT 3
/* ... */
#define E2BIG  7
#define EBUSY  8
/* ... */
#define ECHILD 12
/* ... */

Now, suppose we wish to provide a descriptive error string for each error number. To make sure that the array stays up-to-date with the defines, regardless of any modifications or additions to the header file, we can use this array designation syntax:

char *err_strings[] = {
 	     [0] = "Success",
	[EINVAL] = "Invalid argument",
	[ENOMEM] = "Not enough memory",
	[EFAULT] = "Bad address",
	/* ... */
	[E2BIG ] = "Argument list too long",
	[EBUSY ] = "Device or resource busy",
	/* ... */
	[ECHILD] = "No child processes"
	/* ... */
};

This will statically allocate a sufficient amount of space such that the largest provided index is valid, initialize the specified indices with the provided values, and initialize all other indices to 0.

Structs and Unions

Designated initializers are also useful to initialize fields of structs and unions by name. Suppose we define

struct point {
	int x;
	int y;
	int z;
}

Then, we initialize a struct point with:

struct point p = {.x = 3, .y = 4, .z = 5};

This is particularly useful to generate structures at compile time, rather than being required to call an initialization function, in the case where we don’t want all the fields initialized to 0.

For unions, we can use the same syntax, but we just pick one field to initialize.

Macro Lists

A common idiom in C is to have a list of named entities and need to set up functions for each of them, set up initializers for each of them, and in general expand the name to a variety of different pieces of code. This is quite common on the Mozilla code base, where I picked up the trick. For example, in the project I worked on this past summer, we had a macro list of flags for each instruction. It works like this:

#define FLAG_LIST(_)                   \
    _(InWorklist)                      \
    _(EmittedAtUses)                   \
    _(LoopInvariant)                   \
    _(Commutative)                     \
    _(Movable)                         \
    _(Lowered)                         \
    _(Guard)

This defines a macro called FLAG_LIST, which takes one parameter, which is “traditionally” called _, which is a macro that’s called with each argument in the list. An example usage might be more illustrative. Suppose we define a macro DEFINE_FLAG, like so:

#define DEFINE_FLAG(flag) flag,
   enum Flag {
       None = 0,
       FLAG_LIST(DEFINE_FLAG)
       Total
   };
#undef DEFINE_FLAG

Expanding FLAG_LIST(DEFINE_FLAG) gives us the following:

	enum Flag {
		None = 0,
		DEFINE_FLAG(InWorklist)
		DEFINE_FLAG(EmittedAtUses)
		DEFINE_FLAG(LoopInvariant)
		DEFINE_FLAG(Commutative)
		DEFINE_FLAG(Movable)
		DEFINE_FLAG(Lowered)
		DEFINE_FLAG(Guard)
		Total
	};

Next, expanding the DEFINE_FLAG macro on each argument gives us the enum we want:

	enum Flag {
		None = 0,
		InWorklist,
		EmittedAtUses,
		LoopInvariant,
		Commutative,
		Movable,
		Lowered,
		Guard,
		Total
	};

Next we might want to generate some accessor functions to make working with the list of flags more pleasant:

#define FLAG_ACCESSOR(flag) \
bool is##flag() const {\
    return hasFlags(1 << flag);\
}\
void set##flag() {\
    JS_ASSERT(!hasFlags(1 << flag));\
    setFlags(1 << flag);\
}\
void setNot##flag() {\
    JS_ASSERT(hasFlags(1 << flag));\
    removeFlags(1 << flag);\
}

FLAG_LIST(FLAG_ACCESSOR)
#undef FLAG_ACCESSOR

It might be instructive work out step-by-step what this usage expands to, or spend some time with gcc -E, if this idiom is still confusing.

Compile Time Asserts

This trick isn’t so much a C language feature as a particularly “creative” use of macros. Sometimes, particularly in kernel programming, it is very useful to assert on a condition that can be checked at compile-time, rather than tripping over it at runtime. Unfortunately, C99 doesn’t have any facility for compile-time asserts.

But, we can take advantage of the preprocessor to generate code that will compile (preferably emitting no actual instructions) only if a condition holds. There are a variety of different ways to do this, generally taking advantage of building arrays or structures of negative size. The most popular way seems to be:

/* Force a compilation error if condition is false, but also produce a result
 * (of value 0 and type size_t), so it can be used e.g. in a structure
 * initializer (or wherever else comma expressions aren't permitted). */
/* Linux calls these BUILD_BUG_ON_ZERO/_NULL, which is rather misleading. */
#define STATIC_ZERO_ASSERT(condition) (sizeof(struct { int:-!(condition); })    )
#define STATIC_NULL_ASSERT(condition) ((void *)STATIC_ZERO_ASSERT(condition)    )

/* Force a compilation error if condition is false */
#define STATIC_ASSERT(condition) ((void)STATIC_ZERO_ASSERT(condition))

If (condition) evaluates to a non-zero value (which is truthy, in C), then !(condition) will evaluate to zero, and the code will compile successfully to the size of a structure containing a zero-width bitfield. If (condition) evaluates to 0, which is false in C, then a compilation error will occur when attempting to generate a bitfield of negative width.

The use of this is pretty straightforward. If any assumptions are made which can be statically checked, they can be compile-time asserted. For example, in the flag list above, the set of flags is kept as a uint32_t. So, we could have the following line:

STATIC_ASSERT(Total <= 32)

This expands to:

(void)sizeof(struct { int:-!(Total <= 32) })

Now, suppose it is the case the Total <= 32. Then, -!(Total <= 32) evaluates to 0, so the code is equivalent to

(void)sizeof(struct { int: 0 })

which is valid C code. Suppose instead that there are more than 32 flags. Then, -!(Total <= 32) evaluates to -1. Then we have the equivalent of

(void)sizeof(struct { int: -1 } )

Since the bitfield width is negative, this will guarantee that the build will fail if the number of flags exceeds the space we have for them.