简体   繁体   中英

Confusion with Preprocessor Directives

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 (ie GRANDPARENT_H) would be included in the child.c.

We are just defining the macro GRANDPARENT_H ie

#define GRANDPARENT_H

struct foo {
    int member;
};

but how will its content ie

struct foo {
    int member;
};

be included in the child.c

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM