Please excuse my basic question and poor programming knowledge.
I have an implementation that I need to use in many of my projects. But the included header files are different for different projects.
Say I have spi.h header file to be used in projecta.c and projectb.c. But a particular include (definitions.h) is not required in projectb.c then how do I make this include project specific?
I have seen that is done through #ifdef and #ifndef and directives. But can someone please help me understand how is it done.
Thank you
CodePudding user response:
Say I have spi.h header file to be used in projecta.c and projectb.c. But a particular include (definitions.h) is not required in projectb.c then how do I make this include project specific?
Like this:
// projecta.c
#include "spi.h"
#include "definitions.h"
// projectb.c
#include "spi.h"
There's no need for ifdef
directive.
CodePudding user response:
You can include a certain header depending on an #ifdef
like that:
#ifdef INCL_DEFINITIONS
# include "definitions.h"
#endif
The in the project where you need definitions.h
you have to add -DINCL_DEFINITONS
to the compiler parameters
CodePudding user response:
I have seen that is done through #ifdef and #ifndef and directives.
It can be done through #ifdef
and #ifndef
directives or #if
directives.
The key part of this is you need some way to define preprocessor macros based on what project is being built. A common way this is done is:
- Each project has its own build settings.
- Those build settings include options to pass to the compiler.
- The compiler has options to define preprocessor symbols.
For example, with GCC and Clang, you can use -Dsymbol
to cause symbol
to be defined (with no replacement tokens; it is defined, but the definition is empty) or -Dsymbol
=replacement
to cause it to be defined with the indicated replacement
.
Once you have this, there are choices about how to use it. One choice is for a symbol to be defined if a feature should be included and undefined if not. Then you would have directives such as:
#if defined FeatureX
#include "HeaderForFeatureX.h"
#endif
Another choice is for a symbol to be defined to be 1 if the feature should be included and 0 if not. Then you would have:
#if FeatureX
#include "HeaderForFeatureX.h"
#endif
Historically, some people used the first choice and some people used the second. Because of this, it is common to write your settings and code to cover both of them. When defining a symbol with a compiler option, we will both define it (satisfying the first method) and define it to be 1 (satisfying the second method), as with -DFeatureX=1
. When testing it, we will test with with #if defined FeatureX
because that is true if either choice is used, whereas #if FeatureX
is true only if FeatureX
is defined to be 1, not just defined with empty replacement tokens.
(In a #if
directive, if a token that could be a preprocessor macro name is not a defined preprocessor macro name, it is replaced with 0
. So, if FeatureX
is not defined, #if FeatureX
becomes #if 0
.)
A third choice is to define a symbol to have different values according to the features chosen. For example, we could define ProductLevel
to be 10, 20, or 30, and then use directives such as:
#if 10 <= ProductLevel
#include "Level10Features.h"
#if 20 <= ProductLevel
#include "Level20Features.h"
#if 30 <= ProductLevel
#include "Level30Features.h"
#endif
#endif
#endif
CodePudding user response:
that structure of code called Header guard
, you can see it here Purpose of Header guards