Скажите, пожалуйста, что произойдет, если я включу iostream или любой другой файл заголовка дважды в свой файл. Я знаю, что компилятор не бросает ошибку. Будет ли код добавляться дважды или что происходит внутри? Что на самом деле происходит, когда мы включаем заголовочный файл?
Включая файл заголовка дважды в С++
Ответ 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
(что не является юридическим символом в коде пользователя).
Эти параметры необязательно доступны вам.