Home > Software design >  using ifdef and ifndef directives to include header files
using ifdef and ifndef directives to include header files

Time:12-17

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

  • Related