В чем разница между #include <filename> и #include "filename"?

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

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

36 ответов

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

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

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

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

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

В стандарте 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: любой элемент исходного набора символов, кроме символа новой строки и "

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

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

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

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

В соответствии с Открытой группой Базовые спецификации, выпуск 7,

-I каталог

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

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

#include <file.h> сообщает компилятору о поиске заголовка в каталоге "includes", например, для MinGW компилятор будет искать file.h в C:\MinGW\include\ или там, где установлен ваш компилятор.

#include "file" говорит компилятору искать в текущем каталоге (то есть в каталоге, в котором находится исходный файл) file,

Вы можете использовать -I флаг для GCC, чтобы сказать ему, что, когда он встречает включение с угловыми скобками, он должен также искать заголовки в каталоге после -I, GCC будет обрабатывать каталог после флага, как если бы он был includes каталог.

Например, если у вас есть файл с именем myheader.h в вашем собственном каталоге, вы могли бы сказать, #include <myheader.h> если вы позвонили в GCC с флагом -I . (указывая, что он должен искать включения в текущем каталоге.)

Без -I флаг, вам придется использовать #include "myheader.h" включить файл или переместить myheader.h к include каталог вашей компиляции.

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

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

#include <file>

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

#include "file"

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

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

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

Оно делает:

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

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

а также

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

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

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

<file> include сообщает препроцессору для поиска в -I каталоги и сначала в предопределенных каталогах, затем в каталоге файла.c. "file" include говорит препроцессору сначала выполнить поиск в каталоге исходного файла, а затем вернуться к -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> Форма, если файл не найден. Остальное определяется реализацией.

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

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

    #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 <...> поиск формы (путь включения, например, системные заголовки).

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

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

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

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

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

Как и многие программисты, я использовал неформальное соглашение об использовании "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 переменная окружения.

Когда вы используете #include , препроцессор ищет файл в каталоге заголовочных файлов C\C++ (stdio.h\cstdio, string, vector и т. Д.). Но когда вы используете #include "filename": сначала препроцессор ищет файл в текущем каталоге, а если его нет - ищет его в каталоге заголовочных файлов C\C++.

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

#Include с кавычками будет просто искать файл (и, "в зависимости от реализации", bleh). Это означает, что на обычном английском языке он будет пытаться применить путь / имя файла, который вы выбрасываете в нем, и не будет предварять системный путь или вмешиваться в него в противном случае.

Кроме того, если #include "" не удается, он перечитывается как #include <> по стандарту.

В документации по gcc есть (специфичное для компилятора) описание, которое, хотя и относится к gcc, а не к стандарту, намного проще для понимания, чем разговоры о стандартах ISO в стиле юриста.

  • #include <>для предопределенных заголовочных файлов

Если файл заголовка предопределен, вы просто пишете имя файла заголовка в угловых скобках, и это будет выглядеть так (при условии, что у нас есть предопределенное имя файла заголовка iostream):

#include <iostream>
  • #include " "для заголовочных файлов программист определяет

Если вы (программист) написали свой собственный файл заголовка, вы бы написали имя файла заголовка в кавычках. Итак, предположим, что вы написали заголовочный файл с именем myfile.hтогда это пример того, как вы бы использовали директиву include для включения этого файла:

#include "myfile.h"

Многие из ответов здесь сосредоточены на путях, которые компилятор будет искать, чтобы найти файл. В то время как это то, что делает большинство компиляторов, компилятор, соответствующий ему, может быть предварительно запрограммирован с эффектами стандартных заголовков и обрабатывать, скажем, #include <list> как переключатель, и он вообще не должен существовать как файл.

Это не чисто гипотетически. Есть по крайней мере один компилятор, который работает таким образом. С помощью #include <xxx> рекомендуется только со стандартными заголовками.

#include "filename" // User defined header
#include <filename> // Standard library header.

Пример:

Имя файла здесь Seller.h:

#ifndef SELLER_H     // Header guard
#define SELLER_H     // Header guard

#include <string>
#include <iostream>
#include <iomanip>

class Seller
{
    private:
        char name[31];
        double sales_total;

    public:
        Seller();
        Seller(char[], double);
        char*getName();

#endif

В реализации класса (например, Seller.cppи в других файлах, которые будут использовать файл Seller.h), заголовок, определенный пользователем, теперь должен быть включен следующим образом:

#include "Seller.h"
#include <abc.h>

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

#include "xyz.h"

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

"" будет искать ./ в первую очередь. затем найдите путь включения по умолчанию. вы можете использовать такую ​​команду, чтобы распечатать путь включения по умолчанию:

       gcc -v -o a a.c

вот несколько примеров, чтобы прояснить ситуацию: код ac работает

      // a.c
#include "stdio.h"
int main() {
        int a = 3;
        printf("a = %d\n", a);
        return 0;

}

код bc тоже работает

      \\ b.c
#include <stdio.h>
int main() {
        int a = 3;
        printf("a = %d\n", a);
        return 0;

}

но когда я создаю новый файл с именем stdio.h в текущем каталоге

      // stdio.h
inline int foo()
{
        return 10;
}

ac сгенерирует ошибку компиляции, но bc по-прежнему работает

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

      // d.c
#include <stdio.h>
#include "stdio.h"
int main()
{
        int a = 0;

        a = foo();

        printf("a=%d\n", a);

        return 0;
}

~

#include <file> 

Включает файл, в котором используется каталог включения по умолчанию.

#include "file" 

Включает файл в текущий каталог, в котором он был скомпилирован.

В C++ включить файл можно двумя способами:

Первый - #include, который указывает препроцессору искать файл в предопределенном местоположении по умолчанию. Это местоположение часто является переменной среды INCLUDE, которая обозначает путь для включения файлов.

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

Форма 1 - #include "xxx"

Сначала ищет наличие заголовочного файла в текущем каталоге, откуда вызывается директива. Если он не найден, выполняется поиск в предварительно настроенном списке стандартных системных каталогов.

Форма 2 - #include

Это ищет наличие заголовочного файла в текущем каталоге, откуда вызывается директива.


Точный список каталогов поиска зависит от целевой системы, способа настройки GCC и места его установки. Вы можете найти список каталогов поиска вашего компилятора GCC, запустив его с опцией -v.

Вы можете добавить дополнительные каталоги к пути поиска, используя - Idir, который заставляет искать dir после текущего каталога (для формы директивы в кавычках) и перед стандартными системными каталогами.


По сути, форма "xxx" - это не что иное, как поиск в текущем каталоге; если не найдено, возвращаясь к форме

поиск "" в стандартных местах библиотеки C

тогда как "имя файла" ищет и в текущем каталоге.

В идеале вы должны использовать <...> для стандартных библиотек C и "..." для библиотек, которые вы пишете и присутствуют в текущем каталоге.

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

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

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

#include <filename>

используется, когда вы хотите использовать заголовочный файл системы C/C++ или библиотеки компилятора. Этими библиотеками могут быть stdio.h, string.h, math.h и т. Д.

#include "path-to-file/filename"

используется, когда вы хотите использовать свой собственный файл заголовка, который находится в папке вашего проекта или где-то еще.

Для получения дополнительной информации о препроцессорах и заголовке. Читай С - Препроцессоры.

#include <filename>

  • Препроцессор выполняет поиск в зависимости от реализации. Он сообщает компилятору искать каталог, в котором хранятся файлы системных заголовков.
  • Этот метод обычно используется для поиска стандартных файлов заголовков.

#include "filename"

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

В общем, разница в том, где препроцессор ищет файл заголовка:

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

  1. #include используется для включения файла заголовка системной библиотеки в программу, это означает, что препроцессор C/C++ будет искать имя файла, в котором хранятся файлы библиотеки C или хранятся файлы предопределенных системных заголовков.
  2. #include "filename" используется для включения определяемого пользователем файла заголовка в программу, означает, что препроцессор C/C++ будет искать имя файла в текущем каталоге, в котором находится программа, а затем следует пути поиска, используемому для #include

Проверьте документы gcc, включаемые файлы gcc

Чтобы увидеть порядок поиска в вашей системе, используя gcc, основываясь на текущей конфигурации, вы можете выполнить следующую команду. Вы можете найти более подробную информацию об этой команде здесь

cpp -v /dev/null -o /dev/null

Apple LLVM версия 10.0.0 (clang-1000.10.44.2)
Цель: x86_64-apple-darwin18.0.0
Модель потока: posix Установленный каталог: Библиотека / Разработчик / CommandLineTools / usr / bin
"/ Библиотека / Разработчик /CommandLineTools/usr/bin/clang" -cc1 -тройной x86_64-apple-macosx10.14.0 -Wdeprecated-objc-isa-use -Werror= не рекомендуется-objc-isa-use -E -disable-free - отключить-llvm-верификатор -discard-value-names -main-file-name null -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fno-strict-return -masm-verbose -munwind-tables -target-cpu penryn -dwarf-column-info -debugger-tuning=lldb -target-linker-version 409.12 -v -resource-dir /Library/Developer/CommandLineTools/usr/lib/clang/10.0.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -I/usr/local/include -fdebug-compilation-dir /Users/hogstrom -ferror-limit 19 -fmessage-length 80 -stack-protector 1 -fblocks -fencode-extended-block-signature -fobjc-runtime=macosx-10.14.0 -fmax-type-align=16 -fdiagnostics-show-option -fcolor-диагностика -traditional-cpp -o - -xc / dev / null
clang -cc1 версия 10.0.0 (clang-1000.10.44.2) цель по умолчанию x86_64-apple-darwin18.0.0 игнорируя несуществующий каталог "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/local/include" игнорируя несуществующий каталог "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/Library/Frameworks"
#include "..." поиск начинается здесь:
#include <...> поиск начинается здесь:
/ USR / местные / включить
/Library/Developer/CommandLineTools/usr/lib/clang/10.0.0/include
/ Library / Developer / CommandLineTools / USR / включать
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks (каталог фреймворков)
Конец списка поиска.

Определяемые реализацией предупреждения, генерируемые компилятором, могут (и будут) обрабатывать системные библиотеки иначе, чем программные библиотеки.

Так

#include <myFilename>

- который фактически объявляет, что myFilename находится в расположении системной библиотеки - вполне может (и, вероятно, будет) скрывать мертвый код и предупреждения о неиспользуемых переменных и т. д., которые будут отображаться, когда вы используете:

#include "myFilename"

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