Hi. I'm Jon Jagger.
I help software teams improve their effectiveness.
I built cyber-dojo, the place teams practice programming.
I'm based in the UK.
I've worked in 22 countries.
If you don't like my work, I won't invoice you.
Hire me

Pages

compile time assertions in C

C has a facility for checking dynamic assertions at run-time. It's inside
<assert.h> and its called
assert. Now
assert is a macro, so why isn't it called
ASSERT? I don't know. Prior art no doubt. Anyway,
assert is a
dynamic runtime feature, you can only use it inside functions.

But this doesn't work. The C preprocessor is a glorified text reformatter:
it knows practically nothing about C. However, there is a way to write this
as a compile time assertion (and moving any error trap to an earlier phase
is a Good Thing)

If the expression is true, (an int is at least 32 bits),
the expression
will have a value of one, and constraint will be an array
of one char.
If the assertion is false, (an int is less than 32 bits),
the expression
will have a value of zero, and constraint will be an
empty array. That's
illegal, and you'll get a compile time error. Viola, a compile time assertion :-)
You can use it inside and outside a function but you can't use it twice in
the same function, as you end up with a duplicate definition.
To solve that problem you could resort to some convoluted macro trickery:

But this is pretty horrible. Also, you will probably get warnings about
unused variables. Take a step back for a moment and think about why
it works at all. It's because you have to specify the size of an array as
a compile time constant. The formal grammar of a direct-declarator
tells you this. Let's look at some bits of grammar more closely:

Constrained arrays

I just piggy backed on this, using the constraint that the value of the
constant expression cannot (in this context) be zero. A natural question
(to the curious) is are there other parts of the formal grammar that
require a constant expression. The answer, of course, is yes.

If pred evaluates to true (i.e., 1) then the case
labels will be 0 and 1.
Different; Ok. If pred evaluates to false (i.e., 0) then the
case labels
will be 0 and 0. The same; Compile time error. Viola. However, a
switch
statement cannot exist in the global scope. So the last piece of the puzzle
is to put the compile time assertions inside a function.