Является ли заголовок обязательным файлом?
T.C. оставил интересный комментарий к моему ответу на этот вопрос:
Почему не включить защитников в С++ по умолчанию?
T.C. говорится:
Там "header" и есть "исходный файл". "заголовок" не должен быть фактических файлов.
Что это значит?
Просматривая стандарт, я вижу множество ссылок на "заголовочные файлы" и "заголовки". Однако в отношении #include
я заметил, что стандарт, похоже, ссылается на "заголовки" и "исходные файлы". (С++ 11, § 16.2)
A preprocessing directive of the form
# include < h-char-sequence> new-line
searches a sequence of implementation-defined places for a header identified uniquely
by the specified sequence between the < and > delimiters, and causes the replacement
of that directive by the entire contents of the header. How the places are specified
or the header identified is implementation-defined.
и
A preprocessing directive of the form
# include " q-char-sequence" new-line
causes the replacement of that directive by the entire contents of the source *file*
identified by the specified sequence between the " delimiters. The named source *file*
is searched for in an implementation-defined manner.
Я не знаю, насколько это важно. Может быть, что "заголовки" в контексте С++ однозначно означают "файлы заголовков", но слово "источники" было бы двусмысленным, поэтому "заголовки" являются сокращением, но "источники" - нет. Или может быть, что компилятор С++ разрешен для использования в скобках и должен действовать только так, как если бы имела место текстовая замена.
Итак, когда заголовки (файлы) не являются файлами?
Сноска, упомянутая T.C. в комментариях ниже достаточно прямо:
174) Заголовок не обязательно является исходным файлом, равно как и последовательности ограниченный < и > в именах заголовков обязательно действительный исходный файл имена (16.2).
Ответы
Ответ 1
Для стандартных файлов заголовков стандарт С++ действительно не дает мандата, что компилятор использует файл или файл, если он его использует, на самом деле выглядит как файл С++. Вместо этого стандартные файлы заголовков задаются для создания определенного набора объявлений и определений, доступных для программы на С++.
Альтернативной реализацией файла может быть легко упакованный набор объявлений, представленных в компиляторе, как структура данных, которая становится доступной при использовании соответствующего #include
-directive. Я не знаю какого-либо компилятора, который делает именно это, но clang начал внедрять систему модуля что делает заголовки доступными из уже обработанного формата.
Ответ 2
Они не обязательно должны быть файлами, так как препроцессор C и С++ почти одинаковый, разумно заглянуть в соображение C99 для некоторой ясности в этом вопросе. Если мы посмотрим на Обоснование для языков международного стандартного программирования-C, то это говорит в разделе 7.1.2
Стандартные заголовки говорят (выделено мной):
Во многих реализациях имена заголовков - это имена файлов в специальные каталоги. Этот метод внедрения не требуется, однако: Стандарт не делает никаких предположений о форме, что файл имя может принимать любые системы. Таким образом, заголовки могут иметь особый статус, если реализация так выбирает. Стандартные заголовки могут быть даже встроены в переводчик, при условии, что их содержимое не станет "известным" до тех пор, пока после того, как они явно включены. Одна из целей разрешения этих заголовок "файлы", который должен быть "встроен" в переводчик, должен разрешить реализация языка C в качестве переводчика в самостоятельном где единственной поддержкой файла может быть сетевой интерфейс.
Ответ 3
Это действительно зависит от определения файлов.
Если вы рассматриваете любую базу данных, которая отображает имена файлов в содержимое файловой системы, то да, заголовки - это файлы. Если вы считаете файлы только тем, что распознается системным вызовом ядра ОС open
, то нет, заголовки не обязательно должны быть файлами.
Они могут храниться в реляционной базе данных. Или сжатый архив. Или загружен через сеть. Или хранится в альтернативных потоках или встроенных ресурсах самого исполняемого файла компилятора.
В конце концов, однако, текстовая замена выполняется, и текст поступает из какой-то базы данных с индексированными именами.
Dietmar упомянул модули и загрузил уже обработанный контент... но это, как правило, НЕ допустимое поведение для #include
в соответствии со стандартом С++ (для модулей потребуется использовать другой синтаксис или, возможно, #include
с полностью новой цитатой кроме <>
или ""
). Единственная обработка, которая может быть сделана заранее, - это токенизация. Но содержимое заголовков и включенных исходных файлов подлежит предварительной обработке с сохранением состояния.
Некоторые компиляторы реализуют "предварительно скомпилированные заголовки", которые сделали больше обработки, чем просто токенизация, но в итоге вы обнаружите какое-то поведение, которое нарушает стандарт. Например, в Visual С++:
Компилятор... пропускает только директиву #include
, связанную с файлом .h, использует код, содержащийся в файле .pch, а затем компилирует весь код после имени файла.
Игнорирование исходного кода до #include
определенно не соответствует стандарту. (Это не мешает ему быть полезным, но вы должны знать, что изменения могут не вызывать ожидаемые изменения поведения)