Путаница с директивами препроцессора
У меня три файла
Файл "grandparent.h"
#ifndef GRANDPARENT_H
#define GRANDPARENT_H
struct foo {
int member;
};
#endif /* GRANDPARENT_H */
Файл "parent.h"
#include "grandparent.h"
Файл "child.c"
#include "grandparent.h"
#include "parent.h"
Вики говорит
Здесь первое включение "grandparent.h" приводит к определению макроса GRANDPARENT_H. Затем, когда "child.c" включает в себя "grandparent.h" во второй раз, тест #ifndef возвращает false, и препроцессор переходит к #endif, тем самым избегая второго определения struct foo. Программа компилируется правильно.
q1. "первое включение" grandparent.h "приводит к определению макроса GRANDPARENT_H", так что я понимаю, что это в основном определение макроса с именем GRANDPARENT_H
но я не понимаю, как содержимое этого макроса (например, GRANDPARENT_H) будет включено в child.c.
Мы просто определяем макрос GRANDPARENT_H, т.е.
#define GRANDPARENT_H
struct foo {
int member;
};
но как будет его содержание т.е.
struct foo {
int member;
};
быть включенным в child.c
1 ответ
Если вы "расширить" child.c
вручную, пока нет #include
оставил:
//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 */
Теперь прочитайте это последовательно. Первая строка проверяет, является ли макрос GRANDPARENT_H
определено. Очевидно, что это не так, поскольку это первая инструкция кода.
Вторая строка определяет GRANDPARENT_H
макро. Это пусто, но это не важно, важно то, что оно определено.
Затем код определяет вашу структуру...
Когда препроцессор сталкивается со вторым #ifdef GRANDPARENT_H
макрос уже определен, поэтому он пропускает все содержимое файла, и вы ничего не получите foo redefined
ошибка.
Что подтверждается с помощью -E
возможность увидеть предварительно обработанный child.c
файл:
$ 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
Как видите, структура определяется только один раз.
Обратите внимание, что большинство компиляторов теперь поддерживают более простой способ сделать это: просто вставьте
#pragma once
в начале вашего файла. Как это:
#pragma once
struct foo {
int member;
};
вот и все!