Путаница с включением заголовочных файлов - PullRequest
2 голосов
/ 03 декабря 2011

Когда я включаю заголовочный файл, скажем,

//myheader.h
#ifndef MY_HEADER_H
#define MY_HEADER_H

//....

#endif

в

//mycpp1.cpp
#include "myheader.h"

Что мне говорят, когда mycpp1.cpp включает myheader.h, определяется MY_HEADER_H, поэтому любая попытка включить его снова приведет к ложному результату.

Теперь, если я хочу включить его в mycpp2.cpp.

//mpcpp2.cpp
#include "myheader.h"

Будет ли он включен или использует те же объявления, когда он был включен в первый раз?

Ответы [ 5 ]

6 голосов
/ 03 декабря 2011

Определения препроцессора являются отдельными для каждого файла. Так что, если вы #include myheader.h разделите на два отдельных файла .cpp, они будут включены дважды, а не один раз. Один на .cpp.

4 голосов
/ 03 декабря 2011

Определения препроцессора являются локальными для текущей единицы компиляции.

Конечно, есть сложные случаи, но вот в чем суть:

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

Итак, компиляция N исходных файлов за один прогон, по сути, такова:

[ *.H + SOURCE1.CPP ] --> SOURCE1.O
[ *.H + SOURCE2.CPP ] --> SOURCE2.O
...
[ *.H + SOURCEN.CPP ] --> SOURCEN.O

, где каждая строка представляет собой отдельный блок компиляции , которыйотображает SourceX.CPP и включенные заголовки в объектный файл.Таким образом, мы получили здесь отдельную вещь N.

Таким образом, если вы не измените общие заголовки, вам не придется перекомпилировать неизмененные исходные файлы.Конечно, если вы измените исходный файл, вам придется его перекомпилировать.И, наконец, если вы измените общий заголовок, вам придется перекомпилировать каждый исходный файл, в который он был включен.Здесь я должен упомянуть, что перед фазой компиляции вся строка #inlude "filename.ext" (директива препроцессора ) будет заменена точным содержимым файла filename.ext, каким бы он ни был.

Тогда связывание - это другая проблема, на этом этапе цель состоит в том, чтобы создать один единственный файл из этих N объектных файлов. (повторяю, это простой случай)

Это ссылка:

[ SOURCE1.O + SOURCE2.O + ... + SOURCEN.O ]  --> EXECUTABLE.FILE

Представьте, что затронутые объектные файлы представляют собой пакет значений и алгоритмов ( определения функций ).Например, где-то в пакете должна быть ровно одна функция main ( определение ), поэтому компоновщик точно будет знать, что делать при запуске программы.

Надеюсь, вы получилиэто

Угадайте, что произойдет, если вы запишите определение глобальной функции в файл заголовка, а затем включите его в два отдельных блока компиляции, а затем попытаетесь связать их.

Ответ:ошибка компоновщика - несколько определений, так как вы можете скомпилировать их отдельно.

3 голосов
/ 03 декабря 2011

Если MY_HEADER_H только что определен в mycpp1.cpp, файл заголовка будет включен в mycpp2.cpp

, для чего действительно нужен трюк:

header1.h включает header2.h .
Таким образом, когда вы включаете оба header1.h и header2.h в вашем mycpp.cpp header2.h будет включено дважды, если вы не сделали трюк.

1 голос
/ 03 декабря 2011

Как уже говорилось, заголовочный файл включается один раз для каждого файла .cpp.Но я также хотел упомянуть, что вся цель этого:

#ifndef MY_HEADER_H
#define MY_HEADER_H
// ..
#end if

состоит в том, чтобы предотвратить возникновение проблемы

mycpp1.cpp

#include "myheader.h"
#include "myheader.h"
// ...

Еще одна проблема, с которой у меня возникли проблемы, - это когда вы включаете заголовочный файл в несколько файлов .cpp и определяете в нем глобальные переменные ... вот что я делаю, чтобы решить эту проблему ...

myheader.h

#ifdef MY_HEADER_H
#define MY_HEADER_H

#ifdef GLOBAL_EXTERN
extern int nGlobalInt;
#else
int nGlobalInt = 282;
#endif

#endif

mycpp1.cpp

#include "myheader.h"
// ...

cout << nGlobalInt;

mycpp2.cpp

#define GLOBAL_EXTERN
#include "myheader.h"
// ...

cout << nGlobalInt;

оба файла cpp будут напечатаны 282

0 голосов
/ 03 декабря 2011

Будет включено только один раз.Директива MY_HEADER_H будет определена при первом включении, и все последующие попытки #include myheader.h не будут иметь никакого эффекта.

Директивы препроцессора преобладают над файлами.В противном случае, например, каждый класс, объявленный в myheader.h, будет переопределен.

...