So, what is an assertion? According to gnu.org :
Its a statement in a program that a condition is true at this point in the program. Useful for reasoning about how a program is supposed to behave.
That is, assertions are predicates (or expressions that result in true/false) that programmers add at various places in the code to convey that the specified conditions must be true for the program to continue & execute normally. Assertions can be used to state the precondition – a condition that must hold true before the execution enters a particular code fragment, or postcondition – a condition that must hold true after the execution of a particular code fragment that it follows. These checks would help in early detection of a problem, which might become tricky to detect otherwise.
Assertions mostly work at either compilation time or execution time. While an assertion failure at execution time can abort a running process (in order to avoid a potential catastrophe), the assertion at compile time would cause the build (compilation) itself to fail. Both have their own advantages. Runtime assertions are widely used in C/C++ programs using assert macro. They are checked during the program execution and in case of assertion failure a signal is raised to abort the program. On the other hand compile-time assertions (the subject of this article) work during compilation phase, failure of which results in termination of compilation.
The predicate in compile-time assertion is normally an expression around compile-time constants. They are usually pre-processor macros that inject syntactically invalid code in the program in case of predicate failure & hence the compilation fails.
Lets understand this by taking an example from MySQL code :
#define compile_time_assert(expr) \
typedef char compile_time_assert[(expr) ? 1 : -1] __attribute__((unused)); \
In case the expression (expr) results false, the above macro would create a character array of an invalid size (-1) which would terminate the compilation. Also note that compilation error like ‘redeclaration error’ can be avoided as the array is defined within a do-while loop, opening up the possibility of it being used at multiple places even inside a function or block.
compile_time_assert(sizeof (some_struct) == 12); // sizeof is a compile-time operator.
C11/C++11 standards have added support for compile-time assertions aka ‘static assertions’ by introducing a new keyword static_assert:
static_assert (constant-expression, error-message);
static_assert(sizeof (int) == 8, "A deliberate static assertion..");
$ g++ -std=c++0x static_assert.cpp
static_assert.cpp: In function ‘int main()’:
static_assert.cpp:3:3: error: static assertion failed: "A deliberate static assertion.."
P.S. Here I intentionally omitted an important preprocessor directive #error which can be used to define assertions during preprocessing stage.