В чем разница между #include <filename>и #include "filename"? - PullRequest
2063 голосов
/ 22 августа 2008

В языках программирования C и C ++, в чем разница между использованием угловых скобок и использованием кавычек в операторе include следующим образом?

  1. #include <filename>
  2. #include "filename"

Ответы [ 31 ]

1216 голосов
/ 22 августа 2008

На практике разница заключается в том, где препроцессор ищет включенный файл.

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

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

Более полное описание доступно в документации GCC о путях поиска .

645 голосов
/ 17 сентября 2008

Единственный способ узнать это - прочитать документацию вашей реализации.

В в стандарте C , раздел 6.10.2, параграфы 2-4 указано:

  • Директива предварительной обработки вида

    #include <h-char-sequence> new-line
    

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

  • Директива предварительной обработки вида

    #include "q-char-sequence" new-line
    

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

    #include <h-char-sequence> new-line
    

    с идентичной содержащейся последовательностью (включая > символов, если есть) из оригинала директива.

  • Директива предварительной обработки вида

    #include pp-tokens new-line
    

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

Определения:

  • h-char: любой элемент исходного набора символов, кроме символа новой строки и >

  • q-char: любой элемент исходного набора символов, кроме символа новой строки и "

249 голосов
/ 08 сентября 2008

Последовательность символов между <и> однозначно относится к заголовку, который не обязательно является файлом. Реализации могут свободно использовать последовательность символов по своему желанию. (В основном, однако, просто обработайте его как имя файла и выполните поиск по include пути , как и другие сообщения.)

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

Кроме того, существует третья форма, которая используется, когда директива #include не соответствует ни одной из форм выше. В этой форме некоторая базовая предварительная обработка (например, расширение макроса) выполняется для «операндов» директивы #include, и ожидается, что результат будет соответствовать одной из двух других форм.

100 голосов
/ 20 июля 2012

Некоторые хорошие ответы здесь ссылаются на стандарт C, но забыли стандарт POSIX, особенно специфическое поведение команды c99 (например, компилятор C) .

Согласно Базовые спецификации Open Group Issue 7 ,

-I каталог

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

Итак, в POSIX-совместимой среде с POSIX-совместимым C-компилятором #include "file.h", скорее всего, сначала будет искать ./file.h, где . - каталог, где находится файл с оператором #include, в то время как #include <file.h>, скорее всего, сначала будет искать /usr/include/file.h, где /usr/include - это ваша система, определенная обычных мест для заголовков (кажется, что она не определена в POSIX).

41 голосов
/ 14 января 2017

Документация GCC гласит следующее о разнице между ними:

И пользовательские, и системные заголовочные файлы включены с использованием директивы предварительной обработки ‘#include’. У него есть два варианта:

#include <file>

Этот вариант используется для системных заголовочных файлов. Он ищет файл с именем file в стандартном списке системных каталогов. Вы можете добавить каталоги к этому списку с помощью опции -I (см. Invocation ).

#include "file"

Этот вариант используется для заголовочных файлов вашей собственной программы. Он ищет файл с именем file сначала в каталоге, содержащем текущий файл, затем в каталогах с цитатами и затем в тех же каталогах, которые использовались для <file>. Вы можете добавить каталоги к списку каталогов котировок с помощью опции -iquote. Аргумент ‘#include’, независимо от того, разделены ли они кавычками или угловыми скобками, ведет себя как строковая константа, поскольку комментарии не распознаются, а имена макросов не раскрываются. Таким образом, #include <x/*y> указывает на включение системного заголовочного файла с именем x/*y.

Однако, если в файле происходит обратная косая черта, они считаются обычными текстовыми символами, а не escape-символами. Ни одна из escape-последовательностей символов, соответствующих строковым константам в C, не обрабатывается. Таким образом, #include "x\n\\y" указывает имя файла, содержащее три обратных слеша. (Некоторые системы интерпретируют ‘\ 'как разделитель пути. Все они также интерпретируют ‘/’ одинаково. Наиболее переносимо для использования только ‘/’.)

Ошибка, если в строке после имени файла есть что-либо (кроме комментариев).

40 голосов
/ 08 февраля 2011

Это делает:

"mypath/myfile" is short for ./mypath/myfile

, где . - это либо каталог файла, в котором содержится #include, и / или текущий рабочий каталог компилятора, и / или default_include_paths

и

<mypath/myfile> is short for <defaultincludepaths>/mypath/myfile

Если ./ в <default_include_paths>, то это не имеет значения.

Если mypath/myfile находится в другом каталоге включения, поведение не определено.

30 голосов
/ 03 сентября 2008

Включение <file> указывает препроцессору искать в каталогах -I и в предопределенных каталогах сначала , а затем в каталоге файла .c. Включение "file" указывает препроцессору искать каталог исходного файла сначала , а затем возвращаться к -I и предварительно определенному. Все пункты назначения в любом случае ищутся, отличается только порядок поиска.

Стандарт 2011 года в основном описывает включаемые файлы в «16.2 Включение исходного файла».

2 Директива предварительной обработки вида

# include <h-char-sequence> new-line

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

3 Директива предварительной обработки вида

# include "q-char-sequence" new-line

вызывает замену этой директивы всем содержимым исходного файла, идентифицируемого указанная последовательность между "разделителями". Именованный исходный файл искал в определенной реализации. Если этот поиск не поддерживается или, если поиск не удался, директива обрабатывается как если читать

# include <h-char-sequence> new-line

с идентичной содержащейся последовательностью (включая> символы, если таковые имеются) из исходной директивы.

Обратите внимание, что форма "xxx" ухудшается до формы <xxx>, если файл не найден. Остальное определяется реализацией.

18 голосов
/ 18 августа 2015

По стандарту - да, они разные:

  • Директива предварительной обработки вида

    #include <h-char-sequence> new-line
    

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

  • Директива предварительной обработки вида

    #include "q-char-sequence" new-line
    

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

    #include <h-char-sequence> new-line
    

    с идентичной содержащейся последовательностью (включая > символов, если есть) из оригинала директива.

  • Директива предварительной обработки вида

    #include pp-tokens new-line
    

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

Определения:

  • h-char: любой элемент исходного набора символов, кроме символа новой строки и >

  • q-char: любой элемент исходного набора символов, кроме символа новой строки и "

Обратите внимание, что в стандарте не говорится о какой-либо связи между способами, определяемыми реализацией. Первая форма ищет одним способом, определяемым реализацией, а другой - способом (возможно, другим), определяемым реализацией. Стандарт также указывает, что должны присутствовать определенные включаемые файлы (например, <stdio.h>).

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

15 голосов
/ 15 октября 2014

Спасибо за отличные ответы, особенно. Адам Стельмащик, ПиКуки и Аиб.

Как и многие программисты, я использовал неофициальное соглашение об использовании формы "myApp.hpp" для файлов приложения и формы <libHeader.hpp> для файлов библиотеки и системы компилятора, т.е. файлов, указанных в /I и INCLUDE переменная среды, в течение многих лет считая, что это стандарт.

Однако стандарт C утверждает, что порядок поиска зависит от реализации, что может усложнить переносимость. Что еще хуже, мы используем jam, который автоматически определяет местонахождение включаемых файлов. Вы можете использовать относительные или абсолютные пути для ваших включаемых файлов. т.е.

#include "../../MyProgDir/SourceDir1/someFile.hpp"

В старых версиях MSVS требовалась двойная обратная косая черта (\\), но теперь это не требуется. Я не знаю, когда это изменилось. Просто используйте косую черту для совместимости с 'nix (Windows примет это).

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

Вот пояснение MSDN , скопированное сюда для вашего удобства).

Цитируемая форма

Препроцессор ищет включаемые файлы в следующем порядке:

  1. В том же каталоге, что и файл, содержащий оператор #include.
  2. В каталогах открытых на данный момент включаемых файлов, в обратном порядке, в которых
    они были открыты. Поиск начинается в каталоге родительского включаемого файла и
    продолжается вверх по каталогам любых включаемых файлов прародителя.
  3. Вдоль пути, указанного каждым параметром компилятора /I.
  4. Вдоль путей, указанных в переменной среды INCLUDE.

Форма углового кронштейна

Препроцессор ищет включаемые файлы в следующем порядке:

  1. Вдоль пути, указанного каждым параметром /I компилятора.
  2. Когда компиляция происходит в командной строке, по путям, указанным в переменной среды INCLUDE.
13 голосов
/ 25 октября 2011

По крайней мере для версии GCC <= 3.0 форма угловых скобок не создает зависимости между включаемым файлом и включающим файлом. </p>

Таким образом, если вы хотите сгенерировать правила зависимости (используя опцию GCC -M для примера), вы должны использовать форму в кавычках для файлов, которые должны быть включены в дерево зависимостей.

(см. http://gcc.gnu.org/onlinedocs/cpp/Invocation.html)

...