как избежать дублирования включения заголовочного файла - PullRequest
3 голосов
/ 24 октября 2011

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

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

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

Ответы [ 5 ]

7 голосов
/ 24 октября 2011

Вам необходимо использовать ключевое слово extern:

#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H

extern zend_class_entry * googleset_ce;

#endif // GOOGLESET_PHP_H

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

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

5 голосов
/ 24 октября 2011

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

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

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

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

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

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

это немного лучше, потому что это гарантирует, что переменная действительно глобальная, в некоторых архитектурах (например, Дарвин)иметь, что 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();
1 голос
/ 24 октября 2011

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

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

0 голосов
/ 24 октября 2011

у Люршера есть ответ.Если вы хотите использовать одну и ту же глобальную переменную в файлах .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 */
0 голосов
/ 24 октября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...