Pytanie Jaka jest różnica między #include i #include "filename"?


W językach programowania C i C ++, jaka jest różnica między zastosowaniem nawiasów ostrych a użyciem cudzysłowów w include oświadczenie, jak następuje?

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

1813
2017-08-22 01:40


pochodzenie


gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC6 - legends2k
Gdzie GCC chce znaleźć pliki nagłówkowe - theoretisch


Odpowiedzi:


W praktyce różnica polega na lokalizacji, w której preprocesor wyszukuje dołączony plik.

Dla #include <filename> preprocesor wyszukuje w sposób zależny od implementacji, zwykle w katalogach wyszukiwania wstępnie wyznaczonych przez kompilator / IDE. Ta metoda jest zwykle używana do dołączania standardowych plików nagłówkowych biblioteki.

Dla #include "filename" preprocesor wyszukuje najpierw w tym samym katalogu, co plik zawierający dyrektywę, a następnie podąża za ścieżką wyszukiwania używaną dla pliku #include <filename> Formularz. Ta metoda jest zwykle używana do dołączania plików nagłówkowych zdefiniowanych przez programistę.

Pełniejszy opis jest dostępny w GCC dokumentacja ścieżek wyszukiwania.


1046
2017-08-22 01:40



Oświadczenie: "wyszukiwanie preprocesora w tym samym katalogu ..." może być w praktyce prawdą, ale standard stwierdza, że ​​nazwany plik źródłowy jest "wyszukiwany w sposób określony przez implementację". Zobacz odpowiedź od piCookie. - Richard Corden
Chociaż twoja odpowiedź może wydawać się "prawdziwa", ponieważ tak wiele implementacji działa zgodnie z konwencją, powinieneś przyjrzeć się odpowiedziom aib i piCookie. Obie wskazują (poparte sformułowaniem standardu C), że prawdziwym rozróżnieniem jest włączenie "nagłówka" do włączenia "pliku źródłowego" (i nie, to nie oznacza ".h" vs. ". do"). "Plik źródłowy" w tym kontekście może być (i zazwyczaj jest i prawie zawsze powinien) być plikiem ".h". Nagłówek niekoniecznie musi być plikiem (kompilator może np. Zawierać nagłówek zakodowany statycznie, a nie w pliku). - Dan Moulding
"... preprocesor wyszukuje w tym samym katalogu, w którym kompilowany jest plik, który ma zostać uwzględniony." To stwierdzenie nie jest całkowicie poprawne. Byłem zainteresowany tym pytaniem, ponieważ byłem ciekawy, jaka jest rzeczywista odpowiedź, ale wiem, że to nie jest prawda, ponieważ przynajmniej z gcc, gdy podasz dodatkową ścieżkę dołączania z -I, która wyszuka pliki określone przez #include "filename. h " - Gabriel Southern
Ci, którzy nie lubią odpowiedzi, proszę podać jeden praktyczny przykład, gdzie jest źle. - 0kcats
Rzeczywiście, ostatnio miksowałem te składnie, gdy dodawałem nagłówki z "tej samej" biblioteki i kończyłem z błędami redefinicji. Jeśli poprawnie rozumiem, #include <...> użył pakietu zainstalowanego w systemie i #include "..." użył pobliskiej wersji repozytorium. Mogę mieć te od tyłu. Tak czy inaczej, osłona włączająca w opakowanym nagłówku jest poprzedzona podkreśleniem. (Może to być konwencja dla pakietów lub może celowo zapobiegać miksowaniu dwóch, chociaż kwalifikatory wersji miałyby dla mnie więcej sensu.) - John P


Jedynym sposobem na poznanie jest przeczytanie dokumentacji twojego wdrożenia.

W standard C., sekcja 6.10.2, pkt 2-4 stanowi:

  • Dyrektywa preprocessingowa formularza

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

    przeszukuje sekwencję miejsc zdefiniowanych przez implementację dla nagłówka zidentyfikowanego w sposób unikalny na podstawie określonej sekwencji między < i > ograniczniki i powoduje zastąpienie tej dyrektywy przez całą zawartość nagłówka. Sposób określania miejsc lub zidentyfikowany nagłówek jest zdefiniowany przez implementację.

  • Dyrektywa preprocessingowa formularza

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

    powoduje zastąpienie tej dyrektywy przez całą zawartość pliku źródłowego określonego przez określoną sekwencję między " ograniczniki. Nazwany plik źródłowy jest wyszukiwany w sposób określony przez implementację. Jeśli to wyszukiwanie nie jest obsługiwane lub wyszukiwanie nie powiedzie się, dyrektywa zostanie ponownie przetworzona tak, jakby była czytana

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

    z identyczną zawartą sekwencją (w tym > znaki, jeśli występują) z oryginału   dyrektywa.

  • Dyrektywa preprocessingowa formularza

    #include pp-tokens new-line
    

    (który nie pasuje do jednej z dwóch poprzednich formularzy) jest dozwolone. Tokeny preprocesingu po include w dyrektywie są przetwarzane tak jak w zwykłym tekście. (Każdy identyfikator obecnie zdefiniowany jako nazwa makra zostaje zastąpiony przez listę zastępczą tokenów przetwarzania wstępnego). Dyrektywa wynikowa po wszystkich wymianach musi pasować do jednego z dwóch poprzednich formularzy. Metoda, według której sekwencja żetonów preprocessingu między a < i a > wstępna para tokenów lub para " znaki są łączone na token z pojedynczym nagłówkiem, token wstępnego przetwarzania jest zdefiniowany przez implementację.

Definicje:

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

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


594
2017-09-16 21:06



Istotne: wdrożenie w g ++ i w wizualne c ++ - Alexander Malakhov
@piCookie zarówno <filename>, jak i "filename" wyszukują miejsca zdefiniowane przez implementację. Jaka jest różnica? - onmyway133
@Stefan, właśnie cytuję standard, który nie mówi nic o INCLUDE_PATH. Twoje wdrożenie może to zrobić, a moje może nie. Pierwotne pytanie było generalnie C, a nie gcc (które, jak sądzę, nie używa INCLUDE_PATH) lub Microsoft C (co moim zdaniem robi) ani żadne inne, więc nie można udzielić ogólnej odpowiedzi, ale zamiast tego należy się odwoływać do każdej dokumentacji implementacji. - piCookie
Podobnie jak w przypadku wszystkich tych sytuacji, konkretne przykłady (szczególnie typowych scenariuszy) są bardzo użyteczne i równie docenione. Niepotrzebnie rozwarte ogólne odpowiedzi nie mają tak praktycznego zastosowania. - vargonian
"Oto jak standard C może być rozwlekły i nie odpowiada na twoje pytanie" - anatolyg


Sekwencja znaków między <i> jednoznacznie odnosi się do nagłówka, który niekoniecznie jest plikiem. Wdrożenia mogą dowolnie używać sekwencji znaków, jak chcą. (Przeważnie jednak po prostu traktuj to jako nazwę pliku i przeszukuj w dołącz ścieżkę, jak mówią 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 nie powiedzie się, implementacja zachowuje się tak, jakby druga (#include <file>) został użyty formularz.

Istnieje również trzecia forma, która jest używana, gdy #include dyrektywa nie pasuje do żadnego z powyższych formularzy. W tej formie niektóre podstawowe operacje wstępne (takie jak ekspansja makr) są wykonywane na "operandach" #include dyrektywy, a wynik powinien być zgodny z jedną z dwóch pozostałych form.


215
2017-09-08 17:43



+1, jest to prawdopodobnie najbardziej zwięzła i poprawna odpowiedź tutaj. Zgodnie ze standardem (który piCookie cytuje w swojej odpowiedzi), jedynym real różnica to "nagłówek" a "plik źródłowy". Mechanizm wyszukiwania jest definiowany przez implementację w dowolny sposób. Używanie podwójnych cudzysłowów oznacza, że ​​masz zamiar dołączyć "plik źródłowy", a nawiasy oznaczają, że chcesz umieścić "nagłówek", który, jak mówisz, może w ogóle nie być plikiem. - Dan Moulding
Zobacz komentarz Dana Moldinga do odpowiedzi quest49; standardowe nagłówki nie muszą być w formie pliku, mogą być wbudowane. - aib
Czytałem to "standardowe nagłówki nie muszą być w formie pliku" przez dekadę. Chcesz dostarczyć przykład z prawdziwego świata? - Maxim Egorushkin
@Maxim Yegorushkin: Nie mogę też wymyślić żadnych istniejących przykładów z prawdziwego świata; jednak nie ma kompletnego kompilatora 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 ograniczeniem nazwy pliku "8.3" w systemie MS-DOS. - Dan Moulding
@MaximEgorushkin: kompilator VAX / VMS C przechował wszystkie nagłówki biblioteki wykonawczej C w jednym pliku biblioteki tekstowej (podobnym do archiwum uniksowego) i używał ciągu znaków między < i >jako klucz do indeksu do biblioteki. - Adrian McCarthy


Niektóre dobre odpowiedzi odnoszą się tutaj do standardu C, ale zapomniały o standardzie POSIX, szczególnie o specyficznym zachowaniu c99 (np. kompilator C) dowództwo.

Według Specyfikacja Base Group Open Issue 7,

-JA  informator

Zmień algorytm wyszukiwania nagłówków, których nazwy nie są bezwzględnymi ścieżkami do wyszukiwania w katalogu określonym przez informator ścieżkę przed zaglądnięciem w zwykłe miejsca. Zatem nagłówki, których nazwy są zawarte w podwójnych cudzysłowach (""), są wyszukiwane najpierw w katalogu pliku z #zawierać linii, a następnie w katalogach wymienionych w -JA opcje i ostatnio w zwykłych miejscach. Dla nagłówków, których nazwy są ujęte w nawiasy kwadratowe ("<>"), nagłówek będzie wyszukiwany tylko w katalogach wymienionych w -JA opcje, a następnie w zwykłych miejscach. Katalogi nazwane w -JA opcje będą wyszukiwane w określonej kolejności. Wdrożenia powinny obsługiwać co najmniej dziesięć przypadków tej opcji w jednym c99 wywołanie komendy.

Tak więc, w środowisku zgodnym z POSIX, z kompilatorem C zgodnym z POSIX, #include "file.h" prawdopodobnie będzie szukał ./file.h po pierwsze, gdzie . jest katalogiem, w którym znajduje się plik z #include oświadczenie, natomiast #include <file.h>, prawdopodobnie będzie szukał /usr/include/file.h po pierwsze, gdzie /usr/include jest zdefiniowany twój system zwykłe miejsca dla nagłówków (to nie jest zdefiniowane przez POSIX).


92
2017-07-20 09:29



Jakie jest dokładne źródło tekstu? Czy to normatywna część IEEE Std 1003.1, 2013? - osgx
@osgx: to sformułowanie (lub coś bardzo podobnego) znajduje się w specyfikacji POSIX dla c99 - która jest nazwą POSIX kompilatora C. (Standard POSIX 2008 nie mógł odwoływać się do C11, aktualizacja 2013 do POSIX 2008 nie zmieniła standardu C, do którego się odnosi). - Jonathan Leffler


To robi:

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

z . będący katalogiem pliku, w którym znajduje się #include jest zawarty w i / lub bieżącym katalogu roboczym kompilatora i / lub default_include_paths

i

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

Gdyby ./ jest w <default_include_paths>, to nie robi różnicy.

Gdyby mypath/myfile znajduje się w innym katalogu include, zachowanie jest niezdefiniowane.


36
2018-02-08 11:45



Nie, #include "mypath/myfile" nie jest równoważne #include "./mypath/myfile". Jak mówi piCookie, podwójne cudzysłowy mówią kompilatorowi, aby szukał w sposób zdefiniowany przez implementację - który obejmuje wyszukiwanie w miejscach określonych dla #include <...>. (W rzeczywistości jest to prawdopodobnie odpowiednik, ale tylko dlatego, że na przykład /usr/include/mypath/myfile można określić jako /usr/include/./mypath/myfile - przynajmniej w systemach typu Unix.) - Keith Thompson
@Keith Thompson: Tak, myślałem o moim pudełku z Linuksem. Najwyraźniej mogło być inaczej. Chociaż w praktyce Windows jako system operacyjny inny niż Posix również interpretuje / jako separator ścieżek, i ./ również istnieje. - Stefan Steiger
-L dirpath opcja następnie dodaje dirpath do defaultincludepaths, w przeciwieństwie do nadawania innym znaczenia . (jak wspomniano powyżej). To ma oczekiwaną konsekwencję, że oba #include "..." i #include <...> Szukać w dirpath - Protongun
Myślę, że ta odpowiedź jest niepoprawna, ponieważ sugeruje, że nagłówki zawarte w podwójnych cudzysłowach są zawsze wyszukiwane w bieżącym katalogu roboczym. Mechanizm wyszukiwania jest bardziej szczegółowy; ta odpowiedź jest niepełna. Nie dodaję tego komentarza do skargi lub skomlenie, ale ponieważ system prosi mnie o dodanie komentarza, aby wyjaśnić, dlaczego głosowałem na tę odpowiedź w dół. - Carlo Wood


Dokumentacja GCC mówi poniżej o różnicy między tymi dwoma:

Zarówno pliki nagłówkowe użytkownika, jak i systemowe są zawarte w dyrektywie przetwarzania wstępnego ‘#include’. Ma dwa warianty:

#include <file>

Ten wariant jest używany do plików nagłówkowych systemu. Wyszukuje plik o nazwie w standardowej liście katalogów systemowych. Możesz dodawać katalogi do tej listy za pomocą -I opcja (patrz Wezwanie).

#include "file"

Ten wariant jest używany dla plików nagłówkowych twojego własnego programu. Szuka najpierw pliku o nazwie file w katalogu zawierającym bieżący plik, następnie w katalogach quote, a następnie w tych samych katalogach <file>. Możesz dodawać katalogi do listy katalogów cytatów za pomocą -iquote opcja.     Argument z ‘#include’, niezależnie od tego, czy rozdzielane znakami cudzysłowu, czy nawiasami trójkątnymi, zachowuje się jak stała łańcuchowa, ponieważ komentarze nie są rozpoznawane, a nazwy makr nie są rozszerzane. A zatem, #include <x/*y> określa włączenie pliku nagłówkowego systemu o nazwie x/*y.

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

Jest to błąd, jeśli po nazwie pliku jest coś (innego niż komentarze) w wierszu.


30
2018-01-14 04:52





The <file> include mówi preprocesorowi, aby przeszukał -I katalogi i predefiniowane katalogi pierwszy, a następnie w katalogu plików .c. The "file" include mówi preprocesorowi, aby przeszukał katalog w pliku źródłowym pierwszy, a następnie powróć do -I i wstępnie zdefiniowane. Wszystkie miejsca docelowe są mimo to przeszukane, tylko kolejność wyszukiwania jest inna.

Standard 2011 dotyczy głównie plików włączających w "16.2 Włączanie pliku źródłowego".

2 Dyrektywa preprocessingowa formularza

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

przeszukuje sekwencję miejsc definiowanych przez implementację dla nagłówka zidentyfikowanego w unikalny sposób przez   określona sekwencja między ogranicznikami <i> i powoduje   zastąpienie tej dyrektywy całą treścią nagłówka.   Sposób określania miejsc lub identyfikacja nagłówka   zdefiniowane przez implementację.

3 Dyrektywa preprocessingowa formularza

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

powoduje zastąpienie tej dyrektywy przez całą zawartość pliku źródłowego zidentyfikowanego przez   określona sekwencja między "ogranicznikami." Nazwany plik źródłowy to   wyszukiwane w sposób określony przez implementację. Jeśli to wyszukiwanie   nieobsługiwane lub jeśli wyszukiwanie nie powiedzie się, dyrektywa jest ponownie przetwarzana jako   jeśli to czyta

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

z identyczną zawartą sekwencją (łącznie z> znakami, jeśli istnieją) z pierwotnej dyrektywy.

Zauważ, że "xxx" forma ulega degradacji do <xxx> formularz, jeśli plik nie zostanie znaleziony. Reszta jest definiowana przez implementację.


23
2017-09-03 12:17



Czy możesz podać odniesienie do tego, gdzie w standardzie C to jest -I biznes jest określony? - juanchopanza
@juanchopanza zrobione. Zobacz także odpowiedź od góry :) - Arkadiy
Nie widzę żadnego odniesienia -I. - juanchopanza
To część "zdefiniowana przez implementację". - Arkadiy
Westchnienie. Ja twoja odpowiedź, sprawiłeś, że brzmi to jak coś określonego w tym języku. - juanchopanza


Według standardu - tak, są różne:

  • Dyrektywa preprocessingowa formularza

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

    przeszukuje sekwencję miejsc zdefiniowanych przez implementację dla nagłówka zidentyfikowanego w sposób unikalny na podstawie określonej sekwencji między < i > ograniczniki i powoduje zastąpienie tej dyrektywy przez całą zawartość nagłówka. Sposób określania miejsc lub zidentyfikowany nagłówek jest zdefiniowany przez implementację.

  • Dyrektywa preprocessingowa formularza

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

    powoduje zastąpienie tej dyrektywy przez całą zawartość pliku źródłowego określonego przez określoną sekwencję między " ograniczniki. Nazwany plik źródłowy jest wyszukiwany w sposób określony przez implementację. Jeśli to wyszukiwanie nie jest obsługiwane lub wyszukiwanie nie powiedzie się, dyrektywa zostanie ponownie przetworzona tak, jakby była czytana

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

    z identyczną zawartą sekwencją (w tym > znaki, jeśli występują) z oryginału   dyrektywa.

  • Dyrektywa preprocessingowa formularza

    #include pp-tokens new-line
    

    (który nie pasuje do jednej z dwóch poprzednich formularzy) jest dozwolone. Tokeny preprocesingu po include w dyrektywie są przetwarzane tak jak w zwykłym tekście. (Każdy identyfikator obecnie zdefiniowany jako nazwa makra zostaje zastąpiony przez listę zastępczą tokenów przetwarzania wstępnego). Dyrektywa wynikowa po wszystkich wymianach musi pasować do jednego z dwóch poprzednich formularzy. Metoda, według której sekwencja żetonów preprocessingu między a < i a > wstępna para tokenów lub para " znaki są łączone na token z pojedynczym nagłówkiem, token wstępnego przetwarzania jest zdefiniowany przez implementację.

Definicje:

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

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

Zauważ, że standard nie wskazuje żadnej relacji między sposobami definiowanymi przez implementację. Pierwsza forma wyszukuje w sposób określony przez implementację, a druga w (w inny sposób) określony sposób implementacji. Standard określa również, że niektóre pliki włączające muszą być obecne (na przykład <stdio.h>).

Formalnie musiałbyś przeczytać podręcznik dla swojego kompilatora, jednak normalnie (według tradycji) #include "..." form przeszukuje katalog pliku, w którym znajduje się #include został znaleziony pierwszy, a następnie katalogi, które #include <...> wyszukiwanie formularzy (ścieżka dołączania, np. nagłówki systemowe).


16
2017-08-18 06:21



Jest to głównie ten sam tekst, co odpowiedź piCookie siedem lat wcześniej. - Kyle Strand
@ KyleStrand To dlatego, że ten sam tekst jest cytatem odpowiedniej sekcji w standardzie - tym tekście powinien być identyczne. Faktyczna odpowiedź nie jest tym samym tekstem i jest nieco inna - podczas gdy ja też zdaję sobie sprawę, że zostanie ona napisana w dokumentacji do implementacji, zauważam również, że istnieje również tradycyjny sposób, w jaki są one interpretowane (większość lub wszystkie kompilatory, których używałem). . - skyking
IMO to najlepsza odpowiedź, ponieważ obejmuje zarówno to, co standard mówi, jak i to, co faktycznie robi większość kompilatorów. - plugwash


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

Podobnie jak wielu programistów użyłem nieformalnej konwencji używania "myApp.hpp" formularz dla konkretnych plików aplikacji i <libHeader.hpp> formularz dla bibliotek i plików systemowych kompilatora, tj. pliki określone w /I i INCLUDE zmienna środowiskowa, od lat myśli, że to był standard.

Jednak standard C stwierdza, że ​​kolejność wyszukiwania jest specyficzna dla implementacji, co może skomplikować przenośność. Co gorsza, używamy dżemu, który automagicznie określa, gdzie znajdują się pliki dołączane. Możesz użyć względnych lub bezwzględnych ścieżek dla swoich plików włączających. to znaczy

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

Starsze wersje MSVS wymagały podwójnego ukośnika odwrotnego (\\), ale teraz nie jest to wymagane. Nie wiem, kiedy to się zmieniło. Wystarczy użyć ukośników do przodu, aby uzyskać zgodność z "nix" (Windows to zaakceptuje).

Jeśli jesteś naprawdę martwi się tym, użyj "./myHeader.h" dla pliku włączającego w tym samym katalogu, co kod źródłowy (mój obecny, bardzo duży projekt ma kilka zduplikowanych nazw plików rozproszonych - naprawdę problem z zarządzaniem konfiguracją).

Tutaj jest Wyjaśnienie MSDN skopiowane tutaj dla Twojej wygody).

Cytowany formularz

Preprocesor wyszukuje pliki uwzględnienia w następującej kolejności:

  1. W tym samym katalogu, co plik zawierający instrukcję #include.
  2. W katalogach aktualnie otwieranych zawierają pliki, w odwrotnej kolejności, w której
        zostały otwarte. Wyszukiwanie rozpoczyna się w katalogu nadrzędnego pliku i
        kontynuuje w górę przez katalogi wszystkich plików dołączanych przez grandparent.
  3. Wzdłuż ścieżki określonej przez każdą /I opcja kompilatora.
  4. Wzdłuż ścieżek określonych przez INCLUDE Zmienna środowiskowa.

Formularz kątowy

Preprocesor wyszukuje pliki uwzględnienia w następującej kolejności:

  1. Wzdłuż ścieżki określonej przez każdą /I opcja kompilatora.
  2. Gdy kompilacja występuje w linii poleceń, wzdłuż ścieżek określonych przez INCLUDE Zmienna środowiskowa.

12
2017-10-14 23:51





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

Więc jeśli chcesz generować reguły zależności (używając na przykład opcji GCC -M), musisz użyć cytowanego formularza dla plików, które powinny być zawarte w drzewie zależności.

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


11
2017-10-25 12:35