Thursday, September 20, 2007

Compile-time asserts

I've been pretty busy with the new baby lately and haven't had much time to post anything interesting. That's not necessarily going to change today, but some folks may find this useful anyway.

There are a few ways to do compile-time asserts that work in C and Objective-C. One way is to simply write a macro that evaluates a boolean expression that can be evaluated at compile time, then in the false case, have it do something illegal that the compiler will complain about. For example, below we just declare the macro STATIC_ASSERT, that takes a boolean expression and a message string, and if test evaluates to false, it will try create a typedef for a char array with a negative size. The compiler will complain, and there you'll have your static assert. The message string is used as part of the typedef name as a way to put useful text in the output, but that means it must not contain any spaces.


#define STATIC_ASSERT(test, msg) typedef char _static_assert_ ## msg [ ((test) ? 1 : -1) ]


And we could use it like this:


#define STATIC_ASSERT(test, msg) typedef char _static_assert_ ## msg [ ((test) ? 1 : -1) ]
int main() {
STATIC_ASSERT(sizeof(long) == 4, LONGS_MUST_BE_4_BYTES);
return 0;
}


And if the assertion fails, you'll see an error like this:


$ gcc -o test test.c
test.c: In function 'main':
test.c:4: error: size of array '_static_assert_LONGS_MUST_BE_4_BYTES' is negative


One reason this trick is cool is that you end up with a nice stoic emoticon in your code. Now, if we can just figure out how to get the "Oh my God! There's an ax in my head." k:-O (Thanks Mark D)

UPDATE 10/29: This post talks about a more flexible way to do compile-time assertions