Jaka jest różnica między #include <nazwa pliku> i #include „nazwa pliku”?

2353

Jaka jest różnica w stosowaniu nawiasów kątowych i cudzysłowach w includeinstrukcjach w językach programowania C i C ++ ?

  1. #include <filename>
  2. #include "filename"
quest49
źródło
Aby sprawdzić zachowanie programu Visual Studio, sprawdź: docs.microsoft.com/en-us/cpp/preprocessor/…
smwikipedia

Odpowiedzi:

1403

W praktyce różnica polega na lokalizacji, w której preprocesor szuka dołączonego pliku.

W #include <filename>przypadku wyszukiwania preprocesora w sposób zależny od implementacji, zwykle w katalogach wyszukiwania wstępnie wyznaczonych przez kompilator / IDE. Ta metoda jest zwykle stosowana do dołączania standardowych plików nagłówkowych bibliotek.

Dla #include "filename"wyszukiwań preprocesora pierwszych w tym samym katalogu co plik zawierający dyrektywę, a następnie podąża ścieżką przeszukiwania używana do #include <filename>formularza. Ta metoda jest zwykle stosowana do dołączania plików nagłówkowych zdefiniowanych przez programistę.

Pełniejszy opis znajduje się w dokumentacji GCC na temat ścieżek wyszukiwania .

quest49
źródło
135
Stwierdzenie: „preprocesor szuka w tym samym katalogu ...” może być prawdziwe w praktyce, ale standard stwierdza, że ​​nazwany plik źródłowy jest „wyszukiwany w sposób zdefiniowany w implementacji”. Zobacz odpowiedź piCookie.
Richard Corden,
60
Chociaż twoja odpowiedź może wydawać się „prawdziwa”, ponieważ tyle implementacji działa zgodnie z konwencją, powinieneś dokładnie przyjrzeć się odpowiedziom aib i piCookie. Obaj zwracają uwagę (poparte sformułowaniem standardu C), że prawdziwym rozróżnieniem jest włączenie „nagłówka” w porównaniu z dołączeniem „pliku źródłowego” (i nie, nie oznacza to „.h” vs. ”. do"). „Plik źródłowy” w tym kontekście może być (i zwykle jest i prawie zawsze powinien być) plikiem „.h”. Nagłówek niekoniecznie musi być plikiem (kompilator może np. Zawierać nagłówek, który jest kodowany statycznie, a nie w pliku).
Dan Molding,
5
„... preprocesor szuka w tym samym katalogu co kompilowany plik w celu dołączenia pliku.” To stwierdzenie nie jest całkowicie poprawne. Zainteresowało mnie to pytanie, ponieważ byłem ciekawy, jaka jest prawdziwa odpowiedź, ale wiem, że to nieprawda, ponieważ przynajmniej w przypadku gcc, gdy określasz dodatkową ścieżkę dołączania za pomocą -I, która będzie wyszukiwać pliki określone za pomocą #include "nazwa pliku. h "
Gabriel Southern
9
Ci, którzy nie lubią odpowiedzi, proszę podać jeden praktyczny przykład, w którym jest ona błędna.
0kcats
1
Rzeczywiście, ostatnio zmiksowałem te składnie, dołączając nagłówki z „tej samej” biblioteki i zakończyłem się błędami redefinicji. Jeśli dobrze rozumiem, #include <...>użyłem pakietu zainstalowanego w systemie i #include "..."użyłem pobliskiej wersji repozytorium. Mogę mieć to do tyłu. Tak czy inaczej, osłona włączająca w spakowanym nagłówku jest poprzedzona znakiem podkreślenia. (Może to być konwencja dla pakietów lub może sposób celowego zapobiegania mieszaniu się tych dwóch, chociaż kwalifikatory wersji miałyby dla mnie większy sens).
John P
714

Jedynym sposobem na poznanie jest przeczytanie dokumentacji implementacji.

W normie C sekcja 6.10.2 pkt 2–4 stanowi:

  • Dyrektywa wstępnego przetwarzania formularza

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

    przeszukuje kolejność realizacji zdefiniowanej miejsc na nagłówku jednoznacznie poprzez określonej sekwencji pomiędzy <i >ogranicznikami i powoduje zastąpienie tej dyrektywy przez całą zawartość nagłówka . Sposób określania miejsc lub identyfikowania nagłówka jest zdefiniowany w implementacji.

  • Dyrektywa wstępnego przetwarzania formularza

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

    powoduje zastąpienie tej dyrektywy całą zawartością pliku źródłowego określoną przez określoną sekwencję między "ogranicznikami. Nazwany plik źródłowy jest wyszukiwany w sposób zdefiniowany w implementacji. Jeśli to wyszukiwanie nie jest obsługiwane lub jeśli wyszukiwanie się nie powiedzie, dyrektywa jest przetwarzana ponownie tak, jakby była czytana

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

    z identyczną zawartą sekwencją (w tym >ewentualnymi znakami) z pierwotnej dyrektywy.

  • Dyrektywa wstępnego przetwarzania formularza

    #include pp-tokens new-line

    (który nie pasuje do jednego z dwóch poprzednich formularzy) jest dozwolone. Tokeny przetwarzania wstępnego po includew dyrektywie są przetwarzane tak jak w normalnym tekście. (Każdy identyfikator zdefiniowany obecnie jako nazwa makra jest zastępowany przez zastępczą listę tokenów przetwarzania wstępnego.) Dyrektywa wynikająca z wszystkich zamian musi być zgodna z jedną z dwóch poprzednich form. Sposób, w którym sekwencja przerób znaki między A <i >przerób znacznik pary lub pary z "postaci jest połączony w jedną nazwę nagłówka przerób znacznik jest realizacja określone.

Definicje:

  • h-char: dowolny element źródłowego zestawu znaków oprócz znaku nowej linii i >

  • q-char: dowolny element źródłowego zestawu znaków z wyjątkiem znaku nowej linii i "

piCookie
źródło
108
Istotne: implementacja w g ++ i wizualnym c ++
Alexander Malakhov
27
@piCookie zarówno <nazwa_pliku>, jak i „nazwa_pliku” szukaj miejsc zdefiniowanych w implementacji. Jaka jest różnica?
onmyway133
15
@Stefan, właśnie cytuję standard, który nie mówi nic o INCLUDE_PATH. Twoja implementacja może to zrobić, a moja nie. Pierwotne pytanie brzmiało ogólnie C, a nie konkretnie gcc (co, jak sądzę, nie używa INCLUDE_PATH) lub Microsoft C (co myślę, że tak), ani żadne inne, więc nie można na nie udzielić ogólnej odpowiedzi, ale zamiast tego należy odwołać się do dokumentacji każdego wdrożenia.
piCookie
12
Podobnie jak w przypadku wszystkich tych sytuacji, konkretne przykłady (zwłaszcza typowych scenariuszy) są bardzo przydatne i równie doceniane. Niepotrzebnie tępe ogólne odpowiedzi nie mają tak praktycznego zastosowania.
vargonian
132
„Oto, jak standard C może być pełny i nie odpowiadać na twoje pytanie”
anatolyg
287

Sekwencja znaków między <i> jednoznacznie odnosi się do nagłówka, który niekoniecznie musi być plikiem. Implementacje są w zasadzie dowolne w użyciu sekwencji znaków, jak chcą. (Przeważnie jednak po prostu traktuj to jako nazwę pliku i przeszukaj ścieżkę dołączania , tak jak podają inne posty).

Jeśli #include "file"formularz jest używany, implementacja najpierw szuka pliku o podanej nazwie, jeśli jest obsługiwany. Jeśli nie (obsługiwane) lub jeśli wyszukiwanie się nie powiedzie, implementacja zachowuje się tak, jakby #include <file>użyto innej ( ) formy.

Istnieje również trzeci formularz, który jest używany, gdy #includedyrektywa nie pasuje do żadnego z powyższych formularzy. W tej formie niektóre podstawowe przetwarzanie wstępne (takie jak rozwijanie makr) odbywa się na „operandach” #includedyrektywy, a wynik powinien być zgodny z jedną z dwóch pozostałych postaci.

aib
źródło
50
+1, to chyba najbardziej zwięzła i poprawna odpowiedź tutaj. Zgodnie ze standardem (z którego piCookie cytuje w swojej odpowiedzi) jedyną prawdziwą różnicą jest „nagłówek” w porównaniu z „plikiem źródłowym”. Mechanizm wyszukiwania jest zdefiniowany w obu kierunkach. Użycie podwójnych cudzysłowów oznacza, że ​​zamierzasz dołączyć „plik źródłowy”, podczas gdy nawiasy kątowe oznaczają, że zamierzasz dołączyć „nagłówek”, który, jak mówisz, może wcale nie być plikiem.
Dan Molding,
3
Zobacz komentarz Dana Mouldinga do odpowiedzi quest49; standardowe nagłówki nie muszą być w formie pliku, mogą być wbudowane.
aib
10
Czytam ten „standardowy nagłówek nie musi być w formie pliku” przez dekadę. Chcesz podać prawdziwy przykład?
Maxim Egorushkin
12
@Maxim Yegorushkin: Nie mogę też wymyślić żadnych istniejących przykładów; jednak nie może istnieć kompletny kompilator C11 dla MS-DOS, chyba że nagłówki nie muszą być plikami. Wynika to z faktu, że niektóre nazwy nagłówków C11 nie są zgodne z ograniczeniami nazw plików MS-DOS „8.3”.
Dan Molding
18
@MaximEgorushkin: Kompilator VAX / VMS C przechowywał wszystkie nagłówki bibliotek środowiska wykonawczego C w jednym pliku biblioteki tekstowej (podobnym do archiwum unix) i używał łańcucha między <oraz >jako klucza do indeksowania w bibliotece.
Adrian McCarthy
117

Niektóre dobre odpowiedzi tutaj odnoszą się do standardu C, ale zapomniały o standardzie POSIX, szczególnie specyficzne zachowanie polecenia c99 (np. Kompilatora C) .

Zgodnie z The Open Group Base Specification Issue 7 ,

-I katalog

Zmień algorytm wyszukiwania nagłówków, których nazwy nie są ścieżkami bezwzględnymi, aby przejrzeć katalog o nazwie podanej przez ścieżkę katalogu, zanim przejrzysz zwykłe miejsca. Tak więc nagłówki, których nazwy są ujęte w cudzysłowy („”), należy najpierw wyszukać w katalogu pliku za pomocą wiersza #include , a następnie w katalogach o nazwach w opcjach -I , a na końcu w zwykłych miejscach. W przypadku nagłówków, których nazwy są zawarte w nawiasach kątowych („<>”), nagłówek należy przeszukiwać tylko w katalogach nazwanych w opcjach -I, a następnie w zwykłych miejscach. Katalogi o nazwach w opcjach -I będą przeszukiwane w podanej kolejności.wywołanie polecenia c99 .

Tak więc, w środowisku zgodnym z POSIX, z kompilatorem C zgodnym z POSIX, #include "file.h"prawdopodobnie ./file.hnajpierw szuka , gdzie .jest katalog, w którym znajduje się plik z #includeinstrukcją, a #include <file.h>prawdopodobnie /usr/include/file.hnajpierw szuka , gdzie /usr/includejest zdefiniowany system zwykłe miejsca na nagłówki (wydaje się, że nie jest zdefiniowane przez POSIX).

Yann Droneaud
źródło
1
Jakie jest dokładne źródło tekstu? Czy pochodzi z normatywnej części IEEE Std 1003.1, 2013?
osgx
7
@osgx: to sformułowanie (lub coś bardzo podobnego) znajduje się w specyfikacji POSIX dla c99- która jest nazwą POSIX dla kompilatora C. (Standard POSIX 2008 z trudem mógł odnosić się do C11; aktualizacja POSIX 2008 z 2013 r. Nie zmieniła standardu C, do którego się odwoływał).
Jonathan Leffler,
1
To była moja pierwsza myśl. Strona podręcznika dla gcc zawiera to, podobnie jak inne. Podobnie jest w przypadku bibliotek - -L.
Pryftan
50

Dokumentacja GCC mówi o różnicy między nimi:

Pliki nagłówka użytkownika i systemu są dołączane zgodnie z dyrektywą wstępnego przetwarzania ‘#include’. Ma dwa warianty:

#include <file>

Ten wariant jest używany do plików nagłówków systemowych. Wyszukuje plik o nazwie plik na standardowej liście katalogów systemowych. Możesz dodać katalogi do tej listy za pomocą -Iopcji (zobacz Wywołanie ).

#include "file"

Ten wariant służy do plików nagłówkowych własnego programu. Wyszukuje plik o nazwie plik najpierw w katalogu zawierającym bieżący plik, następnie w katalogach cudzysłowów, a następnie w tych samych katalogach, których użyto <file>. Możesz dodać katalogi do listy katalogów ofert z -iquoteopcją. Argument ‘#include’, niezależnie od tego, czy jest rozdzielany znakami cudzysłowu, czy nawiasami kątowymi, zachowuje się jak stała łańcucha, ponieważ komentarze nie są rozpoznawane, a nazwy makr nie są rozwijane. #include <x/*y>Określa zatem włączenie pliku nagłówka systemowego o nazwie x/*y.

Jeśli jednak w pliku występują ukośniki odwrotne, są one traktowane jako zwykłe znaki tekstowe, a nie znaki specjalne. Żadna z sekwencji ucieczki znaków odpowiednich dla stałych łańcuchowych w C nie jest przetwarzana. W ten sposób #include "x\n\\y"określa nazwę pliku zawierającego trzy backslashy. (Niektóre systemy interpretują „\” jako separator nazw ścieżek. Wszystkie interpretują również w ‘/’ten sam sposób. Najbardziej przenośny jest tylko do użycia ‘/’.)

To jest błąd, jeśli w nazwie po nazwie pliku jest coś (oprócz komentarzy).

Suraj Jain
źródło
46

To robi:

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

gdzie .jest katalogiem pliku, w którym #includejest on zawarty, i / lub bieżącym katalogiem roboczym kompilatora i / lubdefault_include_paths

i

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

Jeśli ./jest włączony <default_include_paths>, to nie ma znaczenia.

Jeśli mypath/myfileznajduje się w innym katalogu dołączania, zachowanie jest niezdefiniowane.

Stefan Steiger
źródło
12
Nie, #include "mypath/myfile"nie jest równoważne z #include "./mypath/myfile". Jak mówi odpowiedź piCookie, podwójne cudzysłowy nakazują kompilatorowi wyszukiwanie w sposób zdefiniowany w implementacji - co obejmuje wyszukiwanie w określonych miejscach #include <...>. (W rzeczywistości jest to prawdopodobnie równoważne, ale tylko dlatego, że na przykład /usr/include/mypath/myfilemożna go określić jako /usr/include/./mypath/myfile- przynajmniej w systemach uniksopodobnych).
Keith Thompson,
1
@Keith Thompson: Zgadza się, myślałem o moim Linux-ie. Najwyraźniej może być inaczej. Chociaż w praktyce Windows jako system operacyjny inny niż Posix również interpretuje / jako separator ścieżek i istnieje również ./.
Stefan Steiger
1
opcja -L ścieżka dirpath następnie dodaje ścieżkę dirpath do defaultincludepaths, w przeciwieństwie do nadawania innego znaczenia .(jak wspomniano powyżej). Ma to oczekiwaną konsekwencję, że zarówno #include "..."i #include <...>poszukiwania w dirpath
Protongun
1
Myślę, że ta odpowiedź jest niepoprawna, ponieważ sugeruje, że nagłówki zawierające podwójne cudzysłowy są zawsze wyszukiwane w bieżącym katalogu roboczym. Mechanizm wyszukiwania jest znacznie bardziej szczegółowy; ta odpowiedź jest niepełna. Nie dodam tego komentarza, aby narzekać lub narzekać, ale ponieważ system prosi mnie o dodanie komentarza wyjaśniającego, dlaczego głosowałem za odrzuceniem tej odpowiedzi.
Carlo Wood
39

The <file> mówi preprocesorowi, aby najpierw przeszukał -Ikatalogi i predefiniowane katalogi , a następnie katalog .c. To mówi preprocesora szukać katalogu plik źródłowy jest pierwszy , a następnie przywrócić i predefiniowane. Wszystkie miejsca docelowe są przeszukiwane, tylko kolejność wyszukiwania jest inna."file"-I

Standard z 2011 r. Omawia głównie pliki dołączane w „Uwzględnieniu plików źródłowych 16,2”.

2 Dyrektywa wstępnego przetwarzania formularza

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

przeszukuje sekwencję miejsc zdefiniowanych w implementacji w poszukiwaniu nagłówka identyfikowanego jednoznacznie przez określoną sekwencję między ogranicznikami <i> i powoduje zastąpienie tej dyrektywy całą treścią nagłówka. Sposób określania miejsc lub identyfikowania nagłówka jest zdefiniowany w implementacji.

3 Dyrektywa wstępnego przetwarzania formularza

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

powoduje zastąpienie tej dyrektywy całą zawartością pliku źródłowego określoną przez określoną sekwencję między ogranicznikami. Wyszukany jest nazwany plik źródłowy w sposób zdefiniowany w implementacji. Jeśli to wyszukiwanie nie jest obsługiwane lub jeśli wyszukiwanie nie powiedzie się , dyrektywa jest przetwarzana ponownie tak, jakby była czytana

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

z identyczną zawartą sekwencją (włączając> znaki, jeśli występują) z pierwotnej dyrektywy.

Zauważ, że "xxx"forma obniża się do <xxx>formy, jeśli plik nie zostanie znaleziony. Reszta jest zdefiniowana w implementacji.


źródło
4
Czy możesz podać odniesienie do tego, gdzie w standardzie C wymieniono tę -Ifirmę?
juanchopanza
1
Nie widzę odniesienia do -I.
juanchopanza
2
To część „zdefiniowana w implementacji”.
27

#include <file.h>mówi kompilatorowi, aby szukał nagłówka w swoim katalogu „obejmuje”, np. w przypadku MinGW kompilator szuka file.hw C: \ MinGW \ include \ lub gdziekolwiek jest zainstalowany kompilator.

#include "file"każe kompilatorowi przeszukać bieżący katalog (tj. katalog, w którym znajduje się plik źródłowy) file.

Możesz użyć -Iflagi dla GCC, aby powiedzieć jej, że gdy napotka inkluzję z nawiasami kątowymi, powinna również wyszukać nagłówki w katalogu po -I. GCC będzie traktować katalog po fladze tak, jakby był includeskatalogiem.

Na przykład, jeśli masz plik wywoływany myheader.hwe własnym katalogu, możesz powiedzieć, #include <myheader.h>czy zadzwoniłeś do GCC z flagą -I .(wskazując, że powinien on szukać zawiera w bieżącym katalogu).

Bez -Iflagi będziesz musiał użyć, #include "myheader.h"aby dołączyć plik lub przejść myheader.hdo includekatalogu kompilatora.

adrian
źródło
22

Standardowo - tak, są różne:

  • Dyrektywa wstępnego przetwarzania formularza

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

    przeszukuje kolejność realizacji zdefiniowanej miejsc dla nagłówka jednoznacznie zidentyfikowane przez podanej kolejności pomiędzy <i >ogranicznikami i powoduje zastąpienie tej dyrektywy przez całą treść nagłówka. Sposób określania miejsc lub identyfikowania nagłówka jest zdefiniowany w implementacji.

  • Dyrektywa wstępnego przetwarzania formularza

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

    powoduje zastąpienie tej dyrektywy całą zawartością pliku źródłowego określoną przez określoną sekwencję między "ogranicznikami. Nazwany plik źródłowy jest wyszukiwany w sposób zdefiniowany w implementacji. Jeśli to wyszukiwanie nie jest obsługiwane lub jeśli wyszukiwanie się nie powiedzie, dyrektywa jest przetwarzana ponownie tak, jakby była czytana

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

    z identyczną zawartą sekwencją (w tym >ewentualnymi znakami) z pierwotnej dyrektywy.

  • Dyrektywa wstępnego przetwarzania formularza

    #include pp-tokens new-line

    (który nie pasuje do jednego z dwóch poprzednich formularzy) jest dozwolone. Tokeny przetwarzania wstępnego po includew dyrektywie są przetwarzane tak jak w normalnym tekście. (Każdy identyfikator zdefiniowany obecnie jako nazwa makra jest zastępowany przez zastępczą listę tokenów przetwarzania wstępnego.) Dyrektywa wynikająca z wszystkich zamian musi być zgodna z jedną z dwóch poprzednich form. Sposób, w którym sekwencja przerób znaki między A <i >przerób znacznik pary lub pary z "postaci jest połączony w jedną nazwę nagłówka przerób znacznik jest realizacja określone.

Definicje:

  • h-char: dowolny element źródłowego zestawu znaków oprócz znaku nowej linii i >

  • q-char: dowolny element źródłowego zestawu znaków z wyjątkiem znaku nowej linii i "

Należy zauważyć, że standard nie określa żadnego związku między sposobami zdefiniowanymi w implementacji. Pierwsza forma wyszukuje w jeden sposób zdefiniowany przez implementację, a drugi w (ewentualnie inny) sposób zdefiniowany przez implementację. Standard określa również, że niektóre pliki dołączane powinny być obecne (na przykład <stdio.h>).

Formalnie trzeba przeczytać instrukcję kompilatora, jednak zwykle (zgodnie z tradycją) #include "..."formularz przeszukuje katalog pliku, w którym #includenajpierw został znaleziony, a następnie katalogi, które #include <...>przeszukuje formularz (zawiera ścieżkę, np. Nagłówki systemowe ).

Król nieba
źródło
2
Jest to w większości ten sam tekst, co odpowiedź piCookie sprzed siedmiu lat .
Kyle Strand
5
@KyleStrand To dlatego, że ten sam tekst jest cytatem odpowiedniej sekcji standardu - ten tekst powinien być identyczny. Rzeczywista odpowiedź nie jest tym samym tekstem i jest nieco inna - choć zdaję sobie również sprawę z tego, że zostanie napisana w dokumentacji do implementacji, zauważam również, że istnieje również tradycyjny sposób ich interpretacji (że większość lub wszystkie kompilatory, których użyłem, szanują) .
skyking
2
IMO to najlepsza odpowiedź tutaj, ponieważ obejmuje ona zarówno to, co mówi standard, jak i to, co faktycznie robi większość kompilatorów.
plugwash
17

Dzięki za wspaniałe odpowiedzi, szczególnie. Adam Stelmaszczyk i piCookie oraz aib.

Podobnie jak wielu programistów, Użyłem nieformalna konwencja pomocą "myApp.hpp"formularza do konkretnych zastosowań plików, oraz <libHeader.hpp>formularz do plików bibliotek systemowych i kompilator, czyli pliki określone w /IaINCLUDE zmienną środowiskową przez lata myślenia, która była średnia.

Jednak standard C mówi, że kolejność wyszukiwania jest specyficzna dla implementacji, co może utrudnić przenoszenie. Co gorsza, używamy jam, który automatycznie rozpoznaje, gdzie znajdują się pliki dołączeń. Możesz użyć względnych lub bezwzględnych ścieżek dla plików dołączanych. to znaczy

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

Starsze wersje MSVS wymagały podwójnych ukośników odwrotnych (\\), ale teraz nie jest to wymagane. Nie wiem kiedy to się zmieniło. Wystarczy użyć ukośników, aby zachować zgodność z 'nix (Windows to zaakceptuje).

Jeśli naprawdę się o to martwisz, użyj "./myHeader.h"pliku dołączenia w tym samym katalogu co kod źródłowy (w moim obecnym, bardzo dużym projekcie są rozproszone zduplikowane nazwy plików dołączonych - to naprawdę problem z zarządzaniem konfiguracją).

Oto wyjaśnienie MSDN skopiowane tutaj dla Twojej wygody).

Cytowany formularz

Preprocesor szuka plików dołączanych w tej kolejności:

  1. W tym samym katalogu, co plik zawierający instrukcję #include.
  2. W katalogach aktualnie otwartych znajdują się pliki w odwrotnej kolejności, w jakiej
    zostały otwarte. Wyszukiwanie rozpoczyna się w katalogu nadrzędnego pliku dołączeń i
    kontynuuje w górę przez katalogi plików dołączonych przez dziadka.
  3. Wzdłuż ścieżki określonej przez każdą /Iopcję kompilatora.
  4. Wzdłuż ścieżek określonych przez INCLUDEzmienną środowiskową.

Forma kątownika

Preprocesor szuka plików dołączanych w tej kolejności:

  1. Wzdłuż ścieżki określonej przez każdą /Iopcję kompilatora.
  2. Gdy kompilacja odbywa się w wierszu poleceń, wzdłuż ścieżek określonych przez INCLUDEzmienną środowiskową.
riderBill
źródło
16

Przynajmniej dla wersji GCC <= 3.0 forma nawiasu kątowego nie generuje zależności między dołączonym plikiem a plikiem zawierającym.

Więc jeśli chcesz wygenerować reguły zależności (na przykład przy użyciu opcji GCC -M), musisz użyć cytowanego formularza dla plików, które powinny zostać uwzględnione w drzewie zależności.

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

Denis Ros
źródło
1
Tak - istnieje kilka różnych sposobów generowania zależności. To jeden z nich, ale nie jedyny.
Pryftan
15

Dla #include ""kompilatora zwykle przeszukuje folder pliku zawierającego że to i wtedy inne foldery. Dla #include <>kompilatora nie wyszukuje folderu bieżącego pliku.

Maxim Egorushkin
źródło
1
Nie jestem pewien, dlaczego ludzie się nie zgadzają.
Maxim Egorushkin
Podejrzewam, że dzieje się tak, ponieważ większość ludzi kompiluje tylko pliki z CWD. Jeśli znajdujesz się w katalogu foo i kompilujesz foo / unittest / bar.c, i zawiera on bar.h, wtedy „bar.h” działa, a <bar.h> nie.
1
@Maksymanie się nie zgadzają, ponieważ opisywane przez ciebie zachowanie nie jest standardem C.
osvein
2
@Spookbuster Racja, standard mówi zarówno, jak <filename>i "filename"szuka miejsc zdefiniowanych w implementacji.
Maxim Egorushkin,
14

Gdy używasz #include <nazwa_pliku>, procesor wstępny szuka pliku w katalogu plików nagłówkowych C \ C ++ (stdio.h \ cstdio, łańcuch, wektor itp.). Ale kiedy użyjesz #include "nazwa_pliku": po pierwsze, procesor wstępny szuka pliku w bieżącym katalogu, a jeśli go nie ma - szuka go w katalogu plików nagłówkowych C \ C ++.

Chayim Friedman
źródło
1
Po tym, jak przez lata dostępna była idealna odpowiedź, po co ją przesyłać, to po prostu rażąco źle? Chociaż powszechna, #includedyrektywa wcale nie jest ściśle związana z plikami.
Widoczny
@Isprawdzalny, proszę wyjaśnić, dlaczego w ogóle nie jest związany z plikami.
Behrooz Karjoo,
11

#Include z nawiasami kątowymi przeszuka „zależną od implementacji listę miejsc” (co jest bardzo skomplikowanym sposobem powiedzenia „nagłówków systemowych”) w celu dołączenia pliku.

#Include z cytatami po prostu wyszuka plik (i „w sposób zależny od implementacji”, bleh). Co oznacza, że ​​w normalnym języku angielskim spróbuje zastosować ścieżkę / nazwę pliku, którą rzucisz na nią, i nie będzie poprzedzać ścieżki systemowej ani w żaden inny sposób nią manipulować.

Ponadto, jeśli #include "" zawiedzie, jest on ponownie odczytywany jako #include <> przez standard.

The gcc ma (specyficzny dla kompilatora) opis, który chociaż jest specyficzny dla gcc, a nie standardu, jest o wiele łatwiejszy do zrozumienia niż rozmowa o standardach ISO w stylu adwokata.

Damon
źródło
Jednak użycie nawiasów kątowych lub cudzysłowów nie wpływa na sposób dołączania plików, jest dokładnie takie samo: preprocesor zasadniczo tworzy duży plik źródłowy, kopiując i wklejając kod z plików dołączanych do oryginalnego pliku źródłowego, przed podaniem do kompilatora (preprocesor robi inne rzeczy, takie jak #define sustitution, #if ewaluacja itp., ale przetwarzanie #include jest takie łatwe)
Loghorn
Co z konfliktami? np. powiedz, że mam zlib.hna ścieżkach wyszukiwania „użytkownik”, a inna ścieżka istnieje w ścieżce wyszukiwania systemu, a następnie #include <zlib.h>obejmuje wersję systemu i #include "zlib.h"własną?
the_mandrill
Aha, odpowiedziałem na własne pytanie: stackoverflow.com/questions/21593/…
the_mandrill
Dziękujemy za potwierdzenie, że zarówno standard (y), jak i typowe konwencje implementacyjne są tutaj istotne, zamiast po prostu stwierdzić, że jest to niepoznawalne, ponieważ nie jest określone przez standard.
Kyle Strand
10
#include "filename" // User defined header
#include <filename> // Standard library header.

Przykład:

Nazwa pliku tutaj to 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

W implementacji klasy (na przykład Seller.cpporaz w innych plikach, które będą korzystały z tego pliku Seller.h), nagłówek zdefiniowany przez użytkownika powinien teraz zostać uwzględniony w następujący sposób:

#include "Seller.h"
Barbara
źródło
10
  • #include <> jest dla predefiniowanych plików nagłówkowych

Jeśli plik nagłówka jest predefiniowany, wystarczy wpisać nazwę pliku nagłówka w nawiasach kwadratowych i wyglądałby tak (zakładając, że mamy wstępnie zdefiniowaną nazwę pliku nagłówka iostream):

#include <iostream>
  • #include " " jest dla plików nagłówkowych definiowanych przez programistę

Jeśli ty (programista) napisałeś swój własny plik nagłówka, wówczas zapisałbyś nazwę pliku nagłówka w cudzysłowie. Załóżmy, że napisałeś plik nagłówka o nazwie myfile.h, to jest przykład użycia dyrektywy include w celu włączenia tego pliku:

#include "myfile.h"
VishalSoni
źródło
2
W ogóle nie ma to nic wspólnego ze wstępnie zdefiniowanymi plikami nagłówkowymi. Ma to związek z lokalizacjami do wyszukiwania.
C Johnson,
9

Wiele odpowiedzi tutaj koncentruje się na ścieżkach, które kompilator będzie szukał w celu znalezienia pliku. Podczas gdy to właśnie robi większość kompilatorów, zgodny kompilator może być wstępnie zaprogramowany z efektami standardowych nagłówków i traktować, powiedzmy,#include <list> jako przełącznik, i wcale nie musi istnieć jako plik.

To nie jest czysto hipotetyczne. W ten sposób działa co najmniej jeden kompilator. #include <xxx>Zalecane jest używanie tylko ze standardowymi nagłówkami.

sp2danny
źródło
9
#include <abc.h>

służy do dołączania standardowych plików bibliotecznych. Kompilator sprawdzi zatem, gdzie znajdują się standardowe nagłówki bibliotek.

#include "xyz.h"

powie kompilatorowi, aby uwzględnił pliki nagłówkowe zdefiniowane przez użytkownika. Tak więc kompilator sprawdzi, czy te pliki nagłówkowe znajdują się w bieżącym folderze lub -Izdefiniowanych folderach.

Christy Wald
źródło
7

W C ++ dołącz plik na dwa sposoby:

Pierwszym jest #include, który mówi preprocesorowi, aby szukał pliku w predefiniowanej domyślnej lokalizacji. Ta lokalizacja jest często zmienną środowiskową INCLUDE, która wskazuje ścieżkę do dołączenia plików.

Drugi typ to #include „nazwa_pliku”, który mówi preprocesorowi, aby najpierw szukał pliku w bieżącym katalogu, a następnie szukał go w predefiniowanych lokalizacjach, które skonfigurował użytkownik.

virat
źródło
7

Formularz 1 - #include <xxx>

Najpierw sprawdza obecność pliku nagłówkowego w bieżącym katalogu, z którego wywoływana jest dyrektywa. Jeśli nie zostanie znaleziony, przeszukuje wstępnie skonfigurowaną listę standardowych katalogów systemowych.

Formularz 2 - #include „xxx”

Wyszukuje obecność pliku nagłówka w bieżącym katalogu, z którego wywoływana jest dyrektywa.


Dokładna lista katalogów wyszukiwania zależy od systemu docelowego, konfiguracji GCC i miejsca instalacji. Możesz znaleźć listę katalogów wyszukiwania swojego kompilatora GCC, uruchamiając go z opcją -v.

Możesz dodać dodatkowe katalogi do ścieżki wyszukiwania, używając - I dir , co powoduje, że dir jest przeszukiwany po bieżącym katalogu (w formie wyceny dyrektywy) i przed standardowymi katalogami systemowymi.


Zasadniczo forma „xxx” jest niczym innym jak wyszukiwaniem w bieżącym katalogu; jeśli nie zostanie znalezione przewrócenie formularza

Darshan L.
źródło
3
Jeśli zdecydujesz się odpowiedzieć na starsze pytanie, które ma dobrze ustalone i poprawne odpowiedzi, dodanie nowej odpowiedzi późno w ciągu dnia może nie przynieść ci uznania. Jeśli masz jakieś nowe, charakterystyczne informacje lub jesteś przekonany, że wszystkie inne odpowiedzi są błędne, dodaj nową odpowiedź, ale „jeszcze jedna odpowiedź”, podając te same podstawowe informacje długo po tym, jak pytanie zostało zadane, zwykle wygrywało ” zarobię ci dużo kredytu.
Jonathan Leffler
1
@Jonathan Leffler Czy możesz wskazać mi „dobrze ugruntowaną” odpowiedź, która Twoim zdaniem jest równie zwięzła i dokładna jak odpowiedź Darshana?
personal_cloud
1
Opis #include "header.h"formularza jest niedokładny, @personal_cloud. Uważam, że odpowiedź piCookie i Yanna Droneauda jest najistotniejsza, ponieważ wskazują, skąd pochodzą ich informacje. Nie wydaje mi się też, aby najlepiej głosowana odpowiedź była w pełni satysfakcjonująca.
Jonathan Leffler
Dlaczego ta odpowiedź jest wyświetlana u góry, podczas gdy dwie odpowiedzi poniżej to ponad 650 głosów? Ta odpowiedź mnie pomyliła, ponieważ nie pasuje do obserwowanego przeze mnie zachowania. Może się tak zdarzyć, ponieważ ostatnie zdanie jest zepsute z powodu braku ucieczki nawiasów kątowych. Nie jestem pewien, co to ma znaczyć.
Neonit
6

#include <filename>Jest używany, gdy system plików jest mowa. Jest to plik nagłówkowy, który można znaleźć w domyślnych lokalizacjach systemu, takich jak /usr/includelub /usr/local/include. W przypadku własnych plików, które muszą być zawarte w innym programie, musisz użyć #include "filename"składni.

srsci
źródło
6

„<nazwa pliku>” wyszukuje w standardowych lokalizacjach biblioteki C.

podczas gdy „nazwa pliku” przeszukuje również bieżący katalog.

Idealnie byłoby użyć <...> dla standardowych bibliotek C i „...” dla bibliotek, które piszesz i są obecne w bieżącym katalogu.

dżigar karangiya
źródło
4
Jakie nowe informacje dodają tę odpowiedź do pozostałych?
Daniel Langr
5

Prostą ogólną zasadą jest stosowanie nawiasów kątowych do dołączania plików nagłówkowych dostarczanych z kompilatorem. Użyj cudzysłowów, aby dołączyć inne pliki nagłówkowe. Większość kompilatorów robi to w ten sposób.

1.9 - Pliki nagłówkowe wyjaśniają bardziej szczegółowo dyrektywy poprzedzające procesor. Jeśli jesteś początkującym programistą, ta strona powinna pomóc Ci to wszystko zrozumieć. Nauczyłem się tego stąd i śledziłem to w pracy.

Eakan Gopalakrishnan
źródło
4
#include <filename>

jest używany, gdy chcesz użyć pliku nagłówka systemu C / C ++ lub bibliotek kompilatora. Bibliotekami tymi mogą być stdio.h, string.h, matematyka.h itp.

#include "path-to-file/filename"

jest używany, gdy chcesz użyć własnego niestandardowego pliku nagłówka, który znajduje się w folderze projektu lub w innym miejscu.

Aby uzyskać więcej informacji na temat preprocesorów i nagłówka. Czytaj C - Preprocesory .

Hafiz Shehbaz Ali
źródło
3

#include <filename>

  • Preprocesor wyszukuje w sposób zależny od implementacji. Mówi kompilatorowi, aby przeszukał katalog, w którym przechowywane są pliki nagłówków systemowych.
  • Ta metoda zwykle służy do wyszukiwania standardowych plików nagłówkowych.

#include "filename"

  • Informuje to kompilator, aby szukał plików nagłówkowych, w których działa program. Jeśli się nie udało, zachowuje się jak#include <filename> i przeszukuje ten plik nagłówka w miejscu, w którym przechowywane są pliki nagłówka systemowego.
  • Ta metoda jest zwykle używana do identyfikacji plików nagłówkowych zdefiniowanych przez użytkownika (pliki nagłówkowe tworzone przez użytkownika). Nie używaj tego, jeśli chcesz wywołać standardową bibliotekę, ponieważ zajmuje to więcej czasu niż kompilacja #include <filename>.
Kalana
źródło
2

Aby zobaczyć kolejność wyszukiwania w systemie za pomocą gcc, w oparciu o bieżącą konfigurację, możesz wykonać następujące polecenie. Więcej informacji na temat tego polecenia można znaleźć tutaj

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

Apple LLVM wersja 10.0.0 (clang-1000.10.44.2)
Cel: x86_64-apple-darwin18.0.0
Model wątku: Posix Zainstalowano : Library / Developer / CommandLineTools / usr / bin
"/ Library / Developer / CommandLineTools / usr / bin / clang" -cc1 -triple x86_64-apple-macosx10.14.0 -Wdeprecated-objc-isa-use -Werror = przestarzałe-objc-isa-use -E -disable-free - disable-llvm-verifier -discard-value-names -main-file-name null -relrel-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 -blocks -fencode-Extended-block-Signature -fobjc-runtime = macosx-10.14.0 -fmax-type-align = 16 -fdiagnostics-show-option -fcolor-diagnostics -traditional-cpp -o - -xc / dev / null
clang -cc1 wersja 10.0.0 (clang-1000.10.44.2) domyślny cel x86_64-apple-darwin18.0.0 ignorowanie nieistniejącego katalogu "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/local/include" ignorowanie nieistniejącego katalog "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/Library/Frameworks"
#include "..." wyszukiwanie rozpoczyna się tutaj:
#include <...> wyszukiwanie rozpoczyna się tutaj:
/ usr / local / include
/ Biblioteka / Developer / CommandLineTools / usr / lib / clang / 10.0.0 / include
/ Library / Developer / CommandLineTools / usr / include
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include
/ Library / Developer / CommandLineTools / SDKs / MacOSX10.14.sdk / System / Library / Frameworks (katalog framework)
Koniec listy wyszukiwania.

Hogstrom
źródło
1
#include <file> 

Zawiera plik, w którym domyślny jest katalog włączania.

#include "file" 

Zawiera plik w bieżącym katalogu, w którym został skompilowany.

IAmAUser
źródło
-2

Istnieją dwa sposoby napisania instrukcji #include. Są to:

#include"filename"
#include<filename>

Znaczenie każdej formy to

#include"mylib.h"

To polecenie szuka pliku mylib.hw bieżącym katalogu, a także podanej listy katalogów, jak wspomniano w ścieżce wyszukiwania dołączania, która mogła zostać skonfigurowana.

#include<mylib.h>

To polecenie szuka pliku tylko mylib.hna określonej liście katalogów.

Ścieżka wyszukiwania dołączania to nic innego jak lista katalogów, które będą wyszukiwane w poszukiwaniu dołączanego pliku. Różne kompilatory C pozwalają ustawić ścieżkę wyszukiwania na różne sposoby.

Noshiii
źródło
1
Jeśli zdecydujesz się odpowiedzieć na starsze pytanie, które ma dobrze ustalone i poprawne odpowiedzi, dodanie nowej odpowiedzi późno w ciągu dnia może nie przynieść ci uznania. Jeśli masz jakieś nowe, charakterystyczne informacje lub jesteś przekonany, że wszystkie inne odpowiedzi są błędne, dodaj nową odpowiedź, ale „jeszcze jedna odpowiedź”, podając tę ​​samą podstawową informację długo po wygraniu pytania, zwykle wygrywa ” zarobię ci dużo kredytu.
Jonathan Leffler