Есть ли стандартное требование для поиска C++ #include?

Недавно я узнал, что gnu cpp и msvc cl лечат #include файлы по разному. Обычным поведением является поиск в каталоге рядом с файлом included_ing_, а затем итерация по пути включения (который, очевидно, устанавливается с помощью -I или же /I аргументы компилятора.)

Но теперь я задаюсь вопросом: правильно ли я учился или на самом деле есть стандарт для препроцессора?

3 ответа

Решение

Согласно стандарту, оба #include <...> а также #include "..." должен искать реализацию определенного набора мест. Нет даже требования, чтобы имя, указанное между <> или же "" это имя файла, просто оно позволяет уникально идентифицировать заголовок.

Сказав, что если реализация хочет иметь какую-либо надежду на компиляцию существующего источника, ей лучше следовать тем же соглашениям, что и остальным: <...> относится к системному включаемому файлу, и "..." относится к вашим собственным включаемым файлам (и каталог, содержащий исходный файл, следует искать в первую очередь). Ни одно из этих требований не является стандартным, но без них у вас нет возможности скомпилировать практически любой существующий код.

Стандарт немного шизофреничен - в одном месте он даст вам инструменты для работы с файлами и каталогами (расширение файловой системы в C++17), в то время как в других он отказывается признать, что такие вещи, как файлы и каталоги, даже существуют, Предположительно, это связано с тем, что авторы не хотят слишком много возиться с древним текстом, поскольку сейчас он работает нормально и может просто случайно что-то сломать, но выглядит немного забавно.

Чтобы расширить ответ Г. Гуджита, ни стандарты языка C или C++ не дают здесь никаких гарантий, но стандарт POSIX действительно предоставляет некоторые дополнительные гарантии того, как cpp (C P repcessor) должен функционировать. Например, в описании-I опция командной строки:

Таким образом, заголовки, имена которых заключены в двойные кавычки ("") должен быть найден первым в каталоге файла с #include линия, затем в каталогах, названных в -I варианты, и последний в обычных местах. Для заголовков, имена которых заключены в угловые скобки ("<>") заголовок нужно искать только в каталогах, названных в -I варианты и то в обычных местах.

Таким образом, любые UNIX-подобные платформы, пытающиеся соответствовать требованиям POSIX, будут вести себя таким образом.

Согласно стандарту (16.2 [cpp.include]/2), #include <...>

ищет последовательность мест, определенных реализацией, для заголовка, уникально идентифицированного указанной последовательностью между < а также > разделители. Как места определяются или как определяется заголовок, определяется реализацией. [выделение добавлено]

В отличие от этого (16,2 [cpp.include]/3), #include "..."

вызывает замену этой директивы всем содержимым исходного файла, идентифицируемого указанной последовательностью между " разделители. Именованный исходный файл ищется в соответствии с реализацией. Если этот поиск не поддерживается или поиск не удался, директива обрабатывается так, как если бы она читалась #include <...> с идентичной содержащейся последовательностью (включая > символы, если таковые имеются) из оригинальной директивы. [выделение добавлено]

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

Важна разница в формулировке: #include <...> не требует исходного файла; полностью зависит от реализации, как он обрабатывает стандартные заголовки. Пользовательские заголовочные файлы должны быть извлечены только с #include "...", поскольку это тот, который требуется для обработки исходных файлов.

По большей части компиляторы реализуют эти вещи так, как вы ожидаете. Критическое различие, которое вы видите с MSVC, заключается в том, что для #include "..." сначала он ищет в каталоге исходного файла верхнего уровня, который компилируется, в то время как другие компиляторы сначала ищут в каталоге исходного файла, который компилируется. Это имеет значение, когда заголовочный файл имеет #include "..." директива: большинство компиляторов ищут в каталоге, где находится заголовочный файл, но MSVC ищет, как если бы #include "..." Директива была в исходном файле верхнего уровня. Оба действительны, и есть аргументы для обоих подходов, хотя я лично нахожу поиск в каталоге, где заголовок, более интуитивным и с ним легче работать.

Другие вопросы по тегам