0

I have three files

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"

Wiki says

Here, the first inclusion of "grandparent.h" causes the macro GRANDPARENT_H to be defined. Then, when "child.c" includes "grandparent.h" the second time, the #ifndef test returns false, and the preprocessor skips down to the #endif, thus avoiding the second definition of struct foo. The program compiles correctly.

q1. "the first inclusion of "grandparent.h" causes the macro GRANDPARENT_H to be defined", So what i understand i its basically defining a macro named GRANDPARENT_H but what i dont understand is that how will the content of that macro (i.e GRANDPARENT_H) would be included in the child.c.

We are just defining the macro GRANDPARENT_H i.e

#define GRANDPARENT_H

struct foo {
    int member;
};

but how will its content i.e

struct foo {
    int member;
};

be included in the child.c

rooni
  • 1,036
  • 3
  • 17
  • 33
  • 2
    it has no value. It's just defined to ensure that the types & functions definitions just are evaluated once by the compiler. – Jean-François Fabre Jan 23 '18 at 12:23
  • @Jean-FrançoisFabre do you mean that the macro GRANDPARENT_H is empty – rooni Jan 23 '18 at 12:24
  • Perhaps what you may want to do is just run your code through the preprocessor, and see how everything is expanded, and yes `GRANDPARENT_H` is empty – Elias Van Ootegem Jan 23 '18 at 12:24
  • @EliasVanOotegem can you help me with that – rooni Jan 23 '18 at 12:24
  • 2
    Just run `gcc -E` to get the code after preprocessor has done its thing, check the documentation for the compiler you're using if not gcc. Clang uses the same `-E` flag it seems (https://clang.llvm.org/docs/CommandGuide/clang.html) – Elias Van Ootegem Jan 23 '18 at 12:26
  • 1
    @rimiro you can write `#define FOO 123`. Then the preprocesseur symbol `FOO` is defined and each time you write `FOO`, `FOO` will be replaced by `123`. But you can also write `#define FOO`. Then the preprocesseur symbol `FOO`is also defined and each time you write `FOO`, `FOO` will be replaced by, you've guessed it, an empty string. – Jabberwocky Jan 23 '18 at 12:30
  • 1
    The content of the macro is only what's beyond it on its line, not the file content. – StoryTeller - Unslander Monica Jan 23 '18 at 12:31

1 Answers1

3

If you "expand" child.c manually until there are no #include left:

//grandparent.h

#ifndef GRANDPARENT_H    // <- not defined at this point
#define GRANDPARENT_H    // <- now it's defined

struct foo {
    int member;
};

#endif /* GRANDPARENT_H */
//parent.h

//#include "grandparent.h" resolves into
//grandparent.h

#ifndef GRANDPARENT_H   // <- already defined, skip until matching #endif
#define GRANDPARENT_H   // <- not executed by preprocessor

struct foo {            // <- not provided to the compiler
    int member;
};

#endif /* GRANDPARENT_H */

now read it sequentially. The first line checks if macro GRANDPARENT_H is defined. Obviously it is not, as it's the first instruction of the code.

The second line defines GRANDPARENT_H macro. It's empty but that's no important, what's important is that it is defined.

Then, the code defines your struct...

When the preprocessor encounters the second #ifdef GRANDPARENT_H, the macro is already defined, so it skips the whole contents of the file and you don't get any foo redefined error.

Which is confirmed by using -E option to see preprocessed child.c file:

$ gcc -E child.c
# 1 "child.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "child.c"
# 1 "grandparent.h" 1


struct foo {
    int member;
};
# 2 "child.c" 2
# 1 "parent.h" 1
# 2 "child.c" 2

as you can see, the structure is only defined once.

Note that most compilers now support a simpler way to do this: just insert

#pragma once

at the start of your file. Like this:

#pragma once

struct foo {
    int member;
};

that's it!

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219