#ifndef directive in C


Reading time: 20 minutes | Coding time: 5 minutes

ifndef is a include guard. It is a define directive in C which checks if a MACRO has been defined previously or not. If it has not been defined, it will define the MACROs and other statements. It is used for conditional compilation.

ifndef can be seen as "if not defined" then do this till endif.

Syntax:

#ifndef <macro_definition>
... some code statements
#endif

It should always end with endif.

Example

In this example, we see a simple use of ifndef for defining a macro named DATA in a C code. As DATA macro is not defined, it will be defined now.

#include <stdio.h>

#ifndef DATA
#define DATA "opengenus" 
#endif

int main()
{
   printf(DATA);
   return 0;
}

Compile it as:

gcc opengenus.c

Output:

opengenus

If we do not end with endif, we will get a compile time error as:

opengenus.c:3:0: error: unterminated #ifndef
 #ifndef DATA
 ^

We can define a global variable in the ifndef block as well like:

#include <stdio.h>

#ifndef DATA
#define DATA "opengenus" 
int global_i = 5;
#endif

int main()
{
   printf("%s\n", DATA);
   printf("%d", global_i);
   return 0;
}

Output:

opengenus
5

In case, the macro DATA is defined previously, then the two code statements of defining DATA macro and global_i variable will not be defined.

For example:

#include <stdio.h>

#define DATA "og"

#ifndef DATA
#define DATA "opengenus" 
int global_i = 5;
#endif

int main()
{
   printf("%s\n", DATA);
   printf("%d", global_i);
   return 0;
}

This will throw a compilation error as global_i will not be defined.
Error:

opengenus.c: In function 'main':
opengenus.c:13:17: error: 'global_i' undeclared (first use in this function)
    printf("%d", global_i);
                 ^
opengenus.c:13:17: note: each undeclared identifier is reported only once for each function it appears in

Let us fix the code:

#include <stdio.h>

#define DATA "og"

#ifndef DATA
#define DATA "opengenus" 
#endif

int main()
{
   printf("%s\n", DATA);
   return 0;
}

Output:

og

The output is og as DATA is defined as og and the second define function is not reached as we are using ifndef.

Example with multiple header files

Consider a header file sodium.h

#ifndef MIXTURE_H
#define MIXTURE_H

struct mineral {
    int saturation;
};

#endif /* MIXTURE_H */

Following it, we have another file say salt.h as:

#ifndef MIXTURE_H
#define MIXTURE_H

struct mineral {
    int saturation;
};struct mineral {
    int saturation;
};

#endif /* MIXTURE_H */

Now in our water.c file, we may either sodium.h or salt.h or both.

#include "salt.h"
#include "sodium.h"

As both sodium.h and salt.h is included and both are using ifndef, there is no problem for the duplicate structure. If we had not used ifndef, there this situation will give an error.

The file water.c will be evaluated as:

struct mineral {
    int saturation;
};

Application

ifndef is widely used as in large codebases, it may not be possible to track.

If we redefine a macro, it will give a compilation error. Consider the following code where we will define the DATA macro twice.

#include <stdio.h>

#define DATA "og"

#define DATA "opengenus" 

int main()
{
   printf("%s\n", DATA);
   return 0;
}

Error:

opengenus.c:5:0: warning: "DATA" redefined
 #define DATA "opengenus" 
 ^
opengenus.c:3:0: note: this is the location of the previous definition
 #define DATA "og"
 ^

MACROs are platform specific as specific MACROs are defined only if certain conditions are satisfied like:

  • operating systems
  • runtime libraries

and others.

Hence, in such scenarios, a code may compile on a certain environment but it will fail in other environment. Hence, to ensure that your code does not fail in any scenario, use ifndef.