Подтвердить что ты не робот

Включая файл заголовка дважды в С++

Скажите, пожалуйста, что произойдет, если я включу iostream или любой другой файл заголовка дважды в свой файл. Я знаю, что компилятор не бросает ошибку. Будет ли код добавляться дважды или что происходит внутри? Что на самом деле происходит, когда мы включаем заголовочный файл?

4b9b3361

Ответ 1

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

Включение защиты - это в основном набор условных директив препроцессора в начале и конце файла заголовка:

#ifndef SOME_STRING_H
#define SOME_STRING_H

//...

#endif 

Теперь, если вы включаете файл дважды, тогда первый макрос SOME_STRING_H не определяется и, следовательно, содержимое файла обрабатывается и рассматривается компилятором. Однако, поскольку первое, что после #ifdef равно #define, определено SOME_STRING_H, а следующий раз содержимое содержимого заголовка не рассматривается компилятором.

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

Ответ 2

Заголовочные файлы - это простые животные. Когда вы #include <header>, все, что происходит, состоит в том, что содержимое header в основном получает копию в файл. Чтобы не включать заголовки в несколько раз, используются include guards, поэтому в большинстве файлов заголовков вы увидите нечто похожее на

#ifndef SOME_HEADER_FILE_GUARD 
#define SOME_HEADER_FILE_GUARD

//Contents of Header

#endif

Ответ 3

Он просто пропускается из-за кода препроцессора в следующих строках:

#ifndef MY_HEADER_H
#define MY_HEADER_H

<actual header code here>

#endif

Итак, если вы включаете дважды, то MY_HEADER_H уже определен, и все между #ifndef и #endif пропускается препроцессором.

Ответ 4

Это зависит. За исключением <assert>, стандарт требует, чтобы второй (и более поздний) включает в себя стандартный заголовок как no-op. Это характеристика заголовка, однако; компилятор будет (по крайней мере концептуально) читать и включать весь текст заголовка каждый раз, когда он сталкивается с включением.

Стандартная практика избежания нескольких определений в таких случаях для использования include guard: весь код С++ в заголовке будет заключен в нечто вроде:

#ifndef SPECIAL_NAME
#define SPECIAL_NAME
//  All of the C++ code here
#endif SPECIAL_NAME

Очевидно, что каждому заголовку требуется другое имя. В приложении, вы можете обычно устанавливать соглашения на основе имени файла и место нахождения; что-то вроде subsystem_filename, с символы, не имеющие юридической силы в символе С++ (если вы используете их в своем имена файлов), отображаемые (и очень часто все верхние). Для библиотек, наилучшей практикой было бы создание достаточно долгого случайная последовательность символов; гораздо чаще (хотя, конечно, уступая с точки зрения качества реализации) заключается в обеспечении того, чтобы каждый такой символ начинается с документированного префикса.

Системная библиотека может, конечно, использовать зарезервированные символы (например, символ начиная с подчеркивания, за которым следует большая буква), здесь, чтобы гарантируйте, что конфликта нет. Или он может использовать некоторые целиком различной, зависящей от реализации техники. Microsoft, например, использует расширение компилятора #pragma once; g++ использует охранники, которые всегда начинайте с _GLIBCXX (что не является юридическим символом в коде пользователя). Эти параметры необязательно доступны вам.