Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static assert in C

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

like image 316
Matt Joiner Avatar asked Aug 02 '10 06:08

Matt Joiner


People also ask

What is static assert in C?

static_assert is used to ensure that a condition is true when the code is compiled. The condition must be a constant expression. In case of failure, an error message is displayed to alert the user. Here's the syntax: static_assert(expression, message); Flow of Events with a static assertion.

How do you assert in C++?

Assertions in C/C++ Following is the syntax for assertion. void assert( int expression ); If the expression evaluates to 0 (false), then the expression, sourcecode filename, and line number are sent to the standard error, and then abort() function is called.


2 Answers

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 
like image 35
Nordic Mainframe Avatar answered Oct 01 '22 18:10

Nordic Mainframe


C11 standard adds the _Static_assert keyword.

This is implemented since gcc-4.6:

_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */ 

The first slot needs to be an integral constant expression. The second slot is a constant string literal which can be long (_Static_assert(0, L"assertion of doom!")).

I should note that this is also implemented in recent versions of clang.

like image 69
emsr Avatar answered Oct 01 '22 20:10

emsr