Является ли заголовок обязательным файлом?

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 определенно не соответствует стандарту. (Это не мешает ему быть полезным, но вы должны знать, что изменения могут не вызывать ожидаемые изменения поведения)