Background
I have C project which has a configuration header file, for example:
// config.h
#define FEATURE_1_AVAILABLE 1
#define FEATURE_2_AVAILABLE 0
#define FEATURE_3_AVAILABLE 1
Modules use these flags to include/exclude features from build:
#include "config.h"
void foo(void) {
...
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
...
There are different versions of config.h
for different builds.
Problem
#include "config.h"
got accidentally removed, so feature wasn't active even when it was enabled in config.
Unfortunately #if FEATURE_1_AVAILABLE
silently evaluates to 0
when it's not defined. So I need an error if it's not defined.
Option 1
I could add extra 'if defined' test on each condition.
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#elif FEATURE_1_AVAILABLE
useFeature1();
#endif
Downside is that one feature flag may be tested in many different places in module, and adding multiple preprocessor lines is not going to make code prettier.
Option 2
Add single test at the beginning of the module:
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#endif
But this can be lost/forgotten for the same reasons that #include "config.h"
was.
Option 3
Define flags as macros:
#define FEATURE_1_AVAILABLE() 1
and use as:
#if FEATURE_1_AVAILABLE()
Unfortunaltely this will also fail silently, if you forget the parenthesis:
#if FEATURE_1_AVAILABLE
Option X
Is there a better option? Something that will give error message at compile time if symbol is not defined or is incorrectly written. And hopefully doesn't make code look unmaintainable preprocessor mess.
Other things
You can request many specific warnings with options beginning with ' -W ', for example -Wimplicit to request warnings on implicit declarations. Each of these specific warning options also has a negative form beginning ' -Wno- ' to turn off warnings; for example, -Wno-implicit .
#warning is a preprocessor directive in C which is used to raise compilation warnings for various situations. It is different from #error directive in that #warning will not cancel the compilation process while #error will cancel it.
A preprocessor error directive causes the preprocessor to generate an error message and causes the compilation to fail. The #error directive is often used in the #else portion of a #if – #elif – #else construct, as a safety check during compilation.
Another solution is to have the compiler warn you if a macro being evaluated is not defined.
With gcc
for example there is the -Wundef
option (not included in -Wall
):
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
this gives the warning (add -Werror
to make it an error):
tst.c:6:9: warning: "FEATURE_1_AVAILABLE" is not defined [-Wundef]
#if FEATURE_1_AVAILABLE
This option is also available with other compilers, e. g., clang
and icc
.
I know it is being frowned upon, but for smaller C projects there is nothing wrong with having one project-wide include file (say myproject.h
) with all your #include ..
directives (like #include "config.h"
) , and then have only #include "myproject.h
at the top of each source file.
Accidentally forgetting this single #include
will usually break the compile immediately, so that won't happen unnoticed.
Alternatively, you could put one essential #include
(say #include assert.h
) in your config.h
(and only there), again to annoy the compiler/linker when you forget to include it
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With