What\'s the best way to achieve compile time static asserts in C (not C++), with particular emphasis on GCC?
For those of you wanting something really basic and portable but don't have access to C++11 features, I've written just the thing.
Use STATIC_ASSERT
normally (you can write it twice in the same function if you want) and use GLOBAL_STATIC_ASSERT
outside of functions with a unique phrase as the first parameter.
#if defined(static_assert)
# define STATIC_ASSERT static_assert
# define GLOBAL_STATIC_ASSERT(a, b, c) static_assert(b, c)
#else
# define STATIC_ASSERT(pred, explanation); {char assert[1/(pred)];(void)assert;}
# define GLOBAL_STATIC_ASSERT(unique, pred, explanation); namespace ASSERTATION {char unique[1/(pred)];}
#endif
GLOBAL_STATIC_ASSERT(first, 1, "Hi");
GLOBAL_STATIC_ASSERT(second, 1, "Hi");
int main(int c, char** v) {
(void)c; (void)v;
STATIC_ASSERT(1 > 0, "yo");
STATIC_ASSERT(1 > 0, "yo");
// STATIC_ASSERT(1 > 2, "yo"); //would compile until you uncomment this one
return 0;
}
Explanation:
First it checks if you have the real assert, which you would definitely want to be using if it's available.
If you don't it asserts by getting your pred
icate, and dividing it by itself. This does two things.
If it's zero, id est, the assertion has failed, it will cause a divide by zero error (the arithmetic is forced because it is trying to declare an array).
If it is not zero, it normalises the array size to 1
. So if the assertion passed, you wouldn't want it to fail anyway because your predicate evaluated to -1
(invalid), or be 232442
(massive waste of space, IDK if it would be optimised out).
For STATIC_ASSERT
it is wrapped in braces, this makes it a block, which scopes the variable assert
, meaning you can write it many times.
It also casts it to void
, which is a known way to get rid of unused variable
warnings.
For GLOBAL_STATIC_ASSERT
, instead of being in a code block, it generates a namespace. Namespaces are allowed outside of functions. A unique
identifier is required to stop any conflicting definitions if you use this one more than once.
Worked for me on GCC and VS'12 C++