views:

248

answers:

2
+7  Q: 

Static assert in C

What's the best way to achieve compile time static asserts in C (not C++), with particular emphasis on GCC?

+1  A: 

From Wikipedia:

#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}

COMPILE_TIME_ASSERT( BOOLEAN CONDITION );
Tyler
It doesn't work outside of functions.
Matt Joiner
It would be better if you linked to the true source: http://www.jaggersoft.com/pubs/CVu11_3.html
Matt Joiner
+12  A: 

This works in function and non-function scope (but not inside structs,unions).

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

STATIC_ASSERT(1,this_should_be_true); 

int main()
{
 STATIC_ASSERT(1,this_should_be_true); 
}
  1. If the compile time assertion could not be matched, then an almost intelligible message is generated by GCC sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative

  2. The macro could or should be changed to generate a unique name for the typedef (i.e. concatenate __LINE__ at the end of the static_assert_... name)

  3. Instead of a ternary, this could be used as well #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1] which happens to work even on the rusty olde cc65 (for the 6502 cpu) compiler.

UPDATE: For completeness sake, here's the version with `LINE

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X)    COMPILE_TIME_ASSERT2(X,__LINE__)

COMPILE_TIME_ASSERT(sizeof(long)==8); 
int main()
{
    COMPILE_TIME_ASSERT(sizeof(int)==4); 
}

UPDATE2: GCC specific code

GCC 4.3 (I guess) introduced the "error" and "warning" function attributes. If a call to a function with that attribute could not be eliminated through dead code elimination (or other measures) then an error or warning is generated. This can be used to make compile time asserts with user defined failure descriptions. It remains to determine how they can be used in namespace scope without resorting to a dummy function:

#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })

// never to be called.    
static void my_constraints()
{
CTC(sizeof(long)==8); 
CTC(sizeof(int)==4); 
}

int main()
{
}

And this is how it looks like:

$ gcc-mp-4.5 -m32 sas.c 
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true
Luther Blissett