Preprocessor – the #error Directive
This is a very useful and often underused preprocessor directive.
Behaviour of this preprocessor directive is the same for both C and C++ compilers.
Purpose
The #error
directive terminates compilation and outputs the text following the directive.
Format
#error text
All preprocessor directives begin with the #
symbol. It must be the first character on the line or the first character on the line following optional white space.
Some early compilers flagged an error if #
was not the first character on the line.
Spaces or tabs are permitted between the #
and error
, but not escape characters or other symbols or macros. The preprocessor removes white space and concatenates the #
and error
together.
If anything follows the #error
directive (other than white space) then the program is malformed.
The following are valid uses:
#error some error message text # error some error text to display # /* comments are white space */ error some error message to display
The following are invalid uses:
// #\ is not a valid preprocessor directive # \t error text to output // #" is not a valid preprocessor directive # "" text to output
Use
It is used to render a program malformed and output the text following the #error
directive. The text may be quoted or unquoted (it doesn’t matter). No macro expansion takes place.
The language specifications do not say how the text following the #error
directive is to be treated.
The GCC compiler, replaces all white space characters between tokens with a single white space character.
I have no reason to believe other compilers behave differently since white space is not considered significant in the C and C++ languages – it serves only to seperate tokens from one another.
There are many times when it is useful to halt compilation:
- code is incomplete
- code requires particular library versions
- code uses compiler dependent features
- code has specific compiler requirements
Incomplete Code
When developing code, it is common to create stub functions. For the final release, these stub functions need to be implemented. We can let the compiler help us catch unimplemented functions:
int my_function( void )
{
#error my_function not implemented
return 0;
}
The above code will fail for every compile. It might be more useful to allow compiling during development, but break the compile when we try to compile a release version. In the following example, we assume that during development, the macro DEBUG
is defined:
int my_function( void )
{
#ifndef DEBUG
#error my_function not implemented
#endif
return 0;
}
During development, we can compile the code, but when we do a release build (one in which DEBUG
is not defined, then we catch unimplemented functions.
Version Checking
Sometimes code is dependent on particular versions of a library. It is useful to be able to stop compilation if an incorrect library version is included:
#if library_version < 2
#error requires library_version 2 or better
#endif
Compiler Dependency
Sometimes, code uses compiler specific features (for example, GCC allows nesting a #define
within another #define
– this is a non-standard compiler feature).
#ifdef __GCC__// some GCC specific code goes here
#else
#error requires GCC compiler to compile
#endif
Compiler Requirements
Sometimes code makes relies on certain assumptions about the target environment (for example, the size of an integer):
#include
#if UINT_MAX != 4294967295
#error this application requires 32 bit integers
#endif