Use of #include guards

File “Grandparent.h”

#ifndef GRANDPARENT_H
#define GRANDPARENT_H

struct Foo {
    int member;
};

#endif /* GRANDPARENT_H */

File “Parent.h”

#include "Grandparent.h"

File “Child.c”

#include "Grandparent.h"
#include "Parent.h"

Intermediate step

// Contents from "Grandparent.h"
#ifndef GRANDPARENT_H // GRANDPARENT_H is not defined
#define GRANDPARENT_H

struct Foo { // This definition is compiled
    int member;
};

#endif /* GRANDPARENT_H */

// Contents from "Parent.h"
#ifndef GRANDPARENT_H // GRANDPARENT_H is already defined
#define GRANDPARENT_H

struct Foo { // This definition is not compiled
    int member;
};

#endif /* GRANDPARENT_H */

Result

struct Foo {
    int member;
};

Here, the first inclusion of “Grandparent.h” has the macro GRANDPARENT_H defined. When “Child.c” includes “Grandparent.h” at the second time (while including “Parent.h”), as the #ifndef test returns false, the preprocessor skips down to the #endif, thus avoiding the second definition of struct Foo. The program compiles correctly.