как избежать повторного включения файла заголовка


У меня есть следующий код:

#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H 
zend_class_entry *googleset_ce;
#endif /* GOOGLESET_PHP_H */

По какой-то причине, если я включаю этот заголовочный файл в более чем один cpp-файл, компилятор кричит, что я объявляю googleset_ce более одного раза. Разве приведенных выше условных макросов не должно быть достаточно, чтобы избежать этого?

5 2

5 ответов:

Вам нужно использовать ключевое слово extern:

#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H

extern zend_class_entry * googleset_ce;

#endif // GOOGLESET_PHP_H

В противном случае компилятор считает, что вы объявляете переменную в каждом файле, содержащем этот заголовок.

Это одна из причин, по которой глобальные переменные не одобряются.

Да, но вы объявляете его только один раз за единицу компиляции.

Включить охрану только убедитесь, что вы объявляете вещи один раз в год .cpp, который его использует.

Таким образом, если A.h входит в B.h и impl.cpp включает оба, то A.h включается только в первый раз.

В вашем случае вы определяете значение макроса include guard как статическую переменную указателя. Так что даже если impl.cpp имеет его только один раз, impl2.cpp, который включает в себя те же файлы, будет иметь их, так что ваш статическая переменная будет иметь повторяющиеся определения во время ссылки

Если вы настаиваете на том, чтобы иметь статические переменные (как сказал Томас, это обычно плохой дизайн), лучше обернуть их в функцию;

myClass* getInstance() {
 static myClass instance;
 return &instance;
 }

Это немного лучше, потому что это гарантирует, что переменная действительно глобальна, некоторые архитектуры (такие как darwin) имеют, что static переменные уникальны для динамической библиотеки, а не для процесса, поэтому это может привести к путанице поведения / переносимости

Также, и более уместно, статические инициализация всегда происходит до main, и порядок не гарантируется. С переменными статической функции переменные инициализируются "по требованию" , и поэтому на них не влияют вопросы порядка инициализации

Для инициализации глобального указателя:

  myClass** getGlobalRef() {
    static myClass* val;
    return &val;
  }

  //and you set it at run-time, avoiding static-initialization happening before main
  * getGlobalRef() = new myClass();

Обратите внимание, что это ошибка компоновщика , а не ошибка компилятора . Вы получаете несколько определенных символов, когда компоновщик пытается собрать вместе объектные файлы (*.o) для всех файлов *.cpp, включая файл заголовка.

Вы, вероятно, обойдете проблему, используя ключевое слово extern, чтобы сделать символ уникальным. И объявляя его где-то еще в одном (и только в одном) файле .cpp.

Если заголовок включен в несколько .с/.cpp файлы, то действительно он потенциально объявлен в нескольких .файлы obj. Вы должны инкапсулировать его в пространство имен или класс, чтобы он не рассматривался как глобальная переменная для каждого из них .cpp файл, который включает его.

У Луршера есть ответ. Если вы хотите совместно использовать одну и ту же глобальную переменную .cpp-файлы, один из способов сделать это-объявить его глобально в одном из ваших .cpp-файлы, а затем объявить его как extern внутри файла заголовка.

Например:

main.cpp
zend_class_entry *googleset_ce = NULL;

googleset.h
#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H
extern zend_class_entry *googleset_ce;
#endif /* GOOGLESET_PHP_H */