Was ist der Unterschied zwischen #include <Dateiname> und #include "Dateiname"?

Antworten:

1405

In der Praxis liegt der Unterschied in dem Speicherort, an dem der Präprozessor nach der enthaltenen Datei sucht.

Für #include <filename>die Präprozessorsuche in implementierungsabhängiger Weise, normalerweise in Suchverzeichnissen, die vom Compiler / der IDE vorab festgelegt wurden. Diese Methode wird normalerweise verwendet, um Standard-Bibliotheksheaderdateien einzuschließen.

Für #include "filename"den Präprozessor sucht zuerst im selben Verzeichnis wie die Datei , die Richtlinie enthält, und dann folgt den Suchpfad für die verwendeten #include <filename>Form. Diese Methode wird normalerweise verwendet, um vom Programmierer definierte Header-Dateien einzuschließen.

Eine ausführlichere Beschreibung finden Sie in der GCC- Dokumentation zu Suchpfaden .

quest49
quelle
135
Die Aussage: "Der Präprozessor sucht im selben Verzeichnis ..." mag in der Praxis zutreffen, aber der Standard besagt, dass die benannte Quelldatei "auf implementierungsdefinierte Weise gesucht" wird. Siehe Antwort von piCookie.
Richard Corden
60
Während Ihre Antwort als "wahr" erscheint, sollten Sie sich die Antworten von aib und piCookie genau ansehen, da so viele Implementierungen gemäß Konvention funktionieren. Beide weisen darauf hin (gestützt auf den Wortlaut des C-Standards), dass der eigentliche Unterschied darin besteht, einen "Header" gegenüber einer "Quelldatei" aufzunehmen (und nein, dies bedeutet nicht ".h" vs. "). c "). "Quelldatei" kann in diesem Zusammenhang eine ".h" -Datei sein (und ist es normalerweise und sollte es fast immer sein). Ein Header muss nicht unbedingt eine Datei sein (ein Compiler kann beispielsweise einen statisch codierten Header enthalten, der nicht in einer Datei enthalten ist).
Dan Moulding
5
"... der Präprozessor sucht im selben Verzeichnis wie die zu kompilierende Datei nach der einzuschließenden Datei." Diese Aussage ist nicht ganz richtig. Ich war an dieser Frage interessiert, weil ich neugierig war, wie die tatsächliche Antwort lautet, aber ich weiß, dass dies nicht der Fall ist, da zumindest bei gcc, wenn Sie einen zusätzlichen Include-Pfad mit -I angeben, nach Dateien gesucht wird, die mit dem Dateinamen #include angegeben sind. h "
Gabriel Southern
9
Diejenigen, die die Antwort nicht mögen, geben bitte ein praktisches Beispiel, wo es falsch ist.
0kcats
1
Sicher genug, ich habe diese Syntax kürzlich gemischt, als ich Header aus derselben Bibliothek einfügte, und am Ende gab es Neudefinitionsfehler. Wenn ich das richtig verstehe, habe ich #include <...>das auf dem System installierte Paket und #include "..."die nahe gelegene Repository-Version verwendet. Ich könnte diese rückwärts haben. In beiden Fällen wird dem Include-Schutz im gepackten Header ein Unterstrich vorangestellt. (Es könnte eine Konvention für Pakete sein oder vielleicht eine Möglichkeit, das Vermischen der beiden absichtlich zu verhindern, obwohl Versionsqualifizierer für mich sinnvoller wären.)
John P
714

Die einzige Möglichkeit, dies zu erfahren, besteht darin, die Dokumentation Ihrer Implementierung zu lesen.

In der C-Norm , Abschnitt 6.10.2, Absätze 2 bis 4 heißt es:

  • Eine Vorverarbeitungsanweisung des Formulars

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

    Durchsucht eine Folge von implementierungsdefinierten Stellen nach einem Header, der durch die angegebene Reihenfolge zwischen dem <und den >Trennzeichen eindeutig identifiziert wird , und ersetzt diese Anweisung durch den gesamten Inhalt des Headers . Wie die Orte angegeben oder der Header identifiziert werden, ist implementierungsdefiniert.

  • Eine Vorverarbeitungsanweisung des Formulars

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

    bewirkt, dass diese Anweisung durch den gesamten Inhalt der Quelldatei ersetzt wird, der durch die angegebene Reihenfolge zwischen den "Trennzeichen gekennzeichnet ist. Die benannte Quelldatei wird implementierungsdefiniert gesucht. Wenn diese Suche nicht unterstützt wird oder wenn die Suche fehlschlägt, wird die Anweisung erneut verarbeitet, als ob sie gelesen würde

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

    mit der identischen enthaltenen Sequenz (einschließlich >Zeichen, falls vorhanden) aus der ursprünglichen Direktive.

  • Eine Vorverarbeitungsanweisung des Formulars

    #include pp-tokens new-line

    (das nicht mit einem der beiden vorherigen Formulare übereinstimmt) ist zulässig. Die Vorverarbeitungstoken nach includeder Direktive werden wie im normalen Text verarbeitet. (Jeder Bezeichner, der derzeit als Makroname definiert ist, wird durch seine Ersetzungsliste von Vorverarbeitungstoken ersetzt.) Die nach allen Ersetzungen resultierende Direktive muss mit einem der beiden vorherigen Formulare übereinstimmen. Die Methode, mit der eine Folge von Vorverarbeitungstoken zwischen einem <und einem >Vorverarbeitungstokenpaar oder einem "Zeichenpaar zu einem Vorverarbeitungstoken mit einem einzelnen Headernamen kombiniert wird, ist implementierungsdefiniert.

Definitionen:

  • h-char: Jedes Mitglied des Quellzeichensatzes mit Ausnahme des Zeilenumbruchs und >

  • q-char: Jedes Mitglied des Quellzeichensatzes mit Ausnahme des Zeilenumbruchs und "

piCookie
quelle
108
Relevant: Implementierung in g ++ und in visuellem c ++
Alexander Malakhov
27
@piCookie Sowohl <Dateiname> als auch "Dateiname" suchen nach implementierungsdefinierten Stellen. Was ist der Unterschied?
onmyway133
15
@Stefan, ich zitiere nur den Standard, der nichts über INCLUDE_PATH aussagt. Ihre Implementierung kann dies tun und meine möglicherweise nicht. Die ursprüngliche Frage war generisch C und nicht spezifisch gcc (was meiner Meinung nach nicht INCLUDE_PATH verwendet) oder Microsoft C (was meiner Meinung nach der Fall ist) oder eine andere, daher kann sie nicht generisch beantwortet werden, sondern auf die Dokumentation jeder Implementierung muss verwiesen werden.
PiCookie
12
Wie in all diesen Situationen sind konkrete Beispiele (insbesondere für gängige Szenarien) sehr nützlich und werden gleichermaßen geschätzt. Unnötig stumpfe generische Antworten haben nicht so viel praktischen Nutzen.
Vargonian
132
"So kann der C-Standard ausführlich sein und Ihre Frage nicht beantworten"
anatolyg
287

Die Zeichenfolge zwischen <und> bezieht sich eindeutig auf einen Header, der nicht unbedingt eine Datei ist. Implementierungen können die Zeichenfolge so gut wie frei verwenden. (Meistens behandeln Sie es jedoch einfach als Dateinamen und führen eine Suche im Include-Pfad durch , wie in den anderen Posts angegeben.)

Wenn das #include "file"Formular verwendet wird, sucht die Implementierung zunächst nach einer Datei mit dem angegebenen Namen, sofern dies unterstützt wird. Wenn dies nicht der Fall ist (unterstützt wird) oder wenn die Suche fehlschlägt, verhält sich die Implementierung so, als ob das andere ( #include <file>) Formular verwendet wurde.

Es gibt auch ein drittes Formular, das verwendet wird, wenn die #includeDirektive keinem der oben genannten Formulare entspricht. In dieser Form werden einige grundlegende Vorverarbeitungen (wie die Makroerweiterung) für die "Operanden" der #includeDirektive durchgeführt, und es wird erwartet, dass das Ergebnis mit einer der beiden anderen Formen übereinstimmt.

aib
quelle
50
+1, dies ist wahrscheinlich die präziseste und korrekteste Antwort hier. Nach dem Standard (aus dem piCookie in seiner Antwort zitiert) ist der einzige wirkliche Unterschied "Header" gegenüber "Quelldatei". Der Suchmechanismus ist in beiden Fällen implementierungsdefiniert. Wenn Sie doppelte Anführungszeichen verwenden, möchten Sie eine "Quelldatei" einfügen, während spitze Klammern bedeuten, dass Sie einen "Header" einfügen möchten, der, wie Sie sagen, möglicherweise überhaupt keine Datei ist.
Dan Moulding
3
Siehe Dan Mouldings Kommentar zur Antwort von quest49; Standardheader müssen nicht in Dateiform vorliegen, sondern können integriert werden.
Aib
10
Ich lese seit einem Jahrzehnt "Standard-Header müssen nicht in Dateiform sein". Möchten Sie ein Beispiel aus der Praxis liefern?
Maxim Egorushkin
12
@ Maxim Yegorushkin: Ich kann mir auch keine Beispiele aus der Praxis vorstellen. Für MS-DOS kann jedoch kein vollständiger C11-Compiler vorhanden sein, es sei denn, Header müssen keine Dateien sein. Dies liegt daran, dass einige der C11-Headernamen nicht mit der Beschränkung des MS-DOS-Dateinamens "8.3" kompatibel sind.
Dan Moulding
18
@MaximEgorushkin: Der VAX / VMS C-Compiler hat alle C-Laufzeitbibliotheksheader in einer einzigen Textbibliotheksdatei (ähnlich einem Unix-Archiv) gespeichert und die Zeichenfolge zwischen <und >als Schlüssel zum Indizieren in die Bibliothek verwendet.
Adrian McCarthy
117

Einige gute Antworten beziehen sich hier auf den C-Standard, haben jedoch den POSIX-Standard vergessen, insbesondere das spezifische Verhalten des Befehls c99 (z. B. C-Compiler) .

Gemäß den Open Group Base Specifications, Ausgabe 7 ,

-Ich Verzeichnis

Ändern Sie den Algorithmus für die Suche nach Headern, deren Namen keine absoluten Pfadnamen sind, so, dass sie in dem Verzeichnis suchen, das durch den Verzeichnispfadnamen benannt ist, bevor Sie an den üblichen Stellen suchen. Daher müssen Header, deren Namen in doppelte Anführungszeichen ("") eingeschlossen sind, zuerst im Verzeichnis der Datei mit der Zeile #include , dann in Verzeichnissen mit den Optionen -I und zuletzt an den üblichen Stellen gesucht werden . Bei Überschriften, deren Namen in spitzen Klammern ("<>") eingeschlossen sind, darf die Überschrift nur in Verzeichnissen gesucht werden, die in den Optionen -I und dann an den üblichen Stellen angegeben sind. In -I- Optionen genannte Verzeichnisse werden in der angegebenen Reihenfolge durchsucht.Aufruf des Befehls c99 .

In einer POSIX-kompatiblen Umgebung mit einem POSIX-kompatiblen C-Compiler #include "file.h"wird wahrscheinlich ./file.hzuerst gesucht , wo .sich das Verzeichnis befindet, in dem sich die Datei mit der #includeAnweisung befindet, während #include <file.h>wahrscheinlich /usr/include/file.hzuerst gesucht wird , wo /usr/includeIhr System definiert ist übliche Stellen für Header (es scheint nicht von POSIX definiert zu sein).

Yann Droneaud
quelle
1
Was ist die genaue Quelle des Textes? Ist es aus dem normativen Teil von IEEE Std 1003.1, 2013?
Osgx
7
@osgx: Dieser Wortlaut (oder etwas sehr Ähnliches) befindet sich in der POSIX-Spezifikation für c99- das ist der POSIX-Name für den C-Compiler. (Der POSIX 2008-Standard konnte sich kaum auf C11 beziehen; das Update 2013 auf POSIX 2008 hat den C-Standard, auf den er sich bezog, nicht geändert.)
Jonathan Leffler
1
Dies war auch mein erster Gedanke. Die Manpage für gcc enthält dies ebenso wie andere. Ähnliches gilt auch für Bibliotheken -L.
Pryftan
50

In der GCC-Dokumentation wird Folgendes über den Unterschied zwischen beiden angegeben:

Sowohl Benutzer- als auch Systemheaderdateien werden mithilfe der Vorverarbeitungsanweisung eingeschlossen ‘#include’. Es gibt zwei Varianten:

#include <file>

Diese Variante wird für Systemheaderdateien verwendet. Es sucht nach einer Datei mit dem Namen file in einer Standardliste von Systemverzeichnissen. Sie können dieser Liste Verzeichnisse mit der -IOption voranstellen (siehe Aufruf ).

#include "file"

Diese Variante wird für Header-Dateien Ihres eigenen Programms verwendet. Es sucht nach einer Datei mit dem Namen file zuerst in dem Verzeichnis, das die aktuelle Datei enthält, dann in den Anführungszeichenverzeichnissen und dann in denselben Verzeichnissen, für die sie verwendet wurde <file>. Mit der -iquoteOption können Sie der Liste der Angebotsverzeichnisse Verzeichnisse voranstellen . Das Argument ‘#include’, ob durch Anführungszeichen oder spitze Klammern begrenzt, verhält sich wie eine Zeichenfolgenkonstante, da Kommentare nicht erkannt und Makronamen nicht erweitert werden. Gibt daher #include <x/*y>die Aufnahme einer Systemheaderdatei mit dem Namen an x/*y.

Wenn jedoch in der Datei Backslashes auftreten, werden diese als normale Textzeichen und nicht als Escapezeichen betrachtet. Keine der Zeichenfolgen-Escape-Sequenzen, die für Zeichenfolgenkonstanten in C geeignet sind, wird verarbeitet. Somit #include "x\n\\y"gibt einen Dateinamen drei Schrägstriche enthält. (Einige Systeme interpretieren '\' als Pfadnamen-Trennzeichen. Alle diese werden auch auf ‘/’die gleiche Weise interpretiert . Es ist am portabelsten, es nur zu verwenden ‘/’.)

Es ist ein Fehler, wenn sich in der Zeile nach dem Dateinamen etwas (außer Kommentaren) befindet.

Suraj Jain
quelle
46

Es tut:

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

Dabei handelt .es sich entweder um das Verzeichnis der Datei, in der sich das #includebefindet, und / oder um das aktuelle Arbeitsverzeichnis des Compilers und / oder um das Verzeichnisdefault_include_paths

und

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

Wenn in ./ist <default_include_paths>, dann macht es keinen Unterschied.

Wenn mypath/myfilees sich in einem anderen Include-Verzeichnis befindet, ist das Verhalten undefiniert.

Stefan Steiger
quelle
12
Nein, #include "mypath/myfile"ist nicht gleichbedeutend mit #include "./mypath/myfile". Wie in der Antwort von piCookie angegeben, weisen doppelte Anführungszeichen den Compiler an, auf implementierungsdefinierte Weise zu suchen - einschließlich der Suche an den angegebenen Stellen #include <...>. (Eigentlich ist es wahrscheinlich gleichwertig, aber nur, weil zum Beispiel /usr/include/mypath/myfileals /usr/include/./mypath/myfile- zumindest auf Unix-ähnlichen Systemen bezeichnet werden kann.)
Keith Thompson
1
@ Keith Thompson: Richtig, ich habe an meine Linux-Box gedacht. Offensichtlich könnte es anders sein. In der Praxis interpretiert Windows als Nicht-Posix-Betriebssystem jedoch auch / als Pfadtrennzeichen, und ./ ist ebenfalls vorhanden.
Stefan Steiger
1
die -L dirpath Option fügt dann dirpath auf den defaultincludepaths, im Gegensatz zu einer anderen Bedeutung der Angabe .(wie oben erwähnt). Dies hat die erwartete Konsequenz, dass beide #include "..."und #include <...>in dirpath
Protongun
1
Ich denke, diese Antwort ist falsch, da sie impliziert, dass in doppelten Anführungszeichen enthaltene Überschriften immer im aktuellen Arbeitsverzeichnis gesucht werden. Der Suchmechanismus ist viel detaillierter; Diese Antwort ist unvollständig. Ich füge diesen Kommentar nicht hinzu, um mich zu beschweren oder zu jammern, sondern weil das System mich auffordert, einen Kommentar hinzuzufügen, um zu erklären, warum ich diese Antwort abgelehnt habe.
Carlo Wood
39

Das <file>sind erzählt die Präprozessor in suchen -IVerzeichnisse und in vordefinierte Verzeichnisse zuerst , dann in das Verzeichnis der C - Datei. Das "file"Include weist den Präprozessor an, zuerst das Verzeichnis der Quelldatei zu durchsuchen und dann zu zurückzukehren-I vordefinierte . Alle Ziele werden trotzdem gesucht, nur die Reihenfolge der Suche ist unterschiedlich.

Der Standard von 2011 behandelt hauptsächlich die Include-Dateien in "16.2 Aufnahme von Quelldateien".

2 Eine Vorverarbeitungsanweisung des Formulars

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

Durchsucht eine Folge von implementierungsdefinierten Stellen nach einem Header, der durch die angegebene Reihenfolge zwischen den Trennzeichen <und> eindeutig identifiziert wird, und bewirkt, dass diese Anweisung durch den gesamten Inhalt des Headers ersetzt wird. Wie die Orte angegeben oder der Header identifiziert werden, ist implementierungsdefiniert.

3 Eine Vorverarbeitungsanweisung des Formulars

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

bewirkt, dass diese Anweisung durch den gesamten Inhalt der Quelldatei ersetzt wird, der durch die angegebene Reihenfolge zwischen den Trennzeichen gekennzeichnet ist. Die benannte Quelldatei wird implementierungsdefiniert gesucht. Wenn diese Suche nicht unterstützt wird oder wenn die Suche fehlschlägt wird die Direktive so wiederaufbereitet, als würde sie lesen

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

mit der identischen enthaltenen Sequenz (einschließlich> Zeichen, falls vorhanden) aus der ursprünglichen Direktive.

Beachten Sie, dass "xxx"sich das <xxx>Formular zu einem Formular verschlechtert, wenn die Datei nicht gefunden wird. Der Rest ist implementierungsdefiniert.


quelle
4
Können Sie einen Verweis darauf geben, wo im C-Standard dieses -IGeschäft angegeben ist?
Juanchopanza
1
Ich sehe keinen Hinweis auf -I.
Juanchopanza
2
Das ist ein "implementierungsdefinierter" Teil.
28

#include <file.h>Weist den Compiler an, nach dem Header in seinem "Includes" -Verzeichnis zu suchen, z. B. nach MinGW, nach dem der Compiler file.hin C: \ MinGW \ include \ suchen würde, oder wo immer Ihr Compiler installiert ist.

#include "file"Weist den Compiler an, das aktuelle Verzeichnis (dh das Verzeichnis, in dem sich die Quelldatei befindet) zu durchsuchen file.

Sie können das -IFlag für GCC verwenden, um anzugeben, dass bei einem Einschluss mit spitzen Klammern auch nach Headern im Verzeichnis danach gesucht werden soll-I . GCC behandelt das Verzeichnis nach dem Flag so, als wäre es das includesVerzeichnis.

Wenn Sie beispielsweise eine Datei myheader.hin Ihrem eigenen Verzeichnis haben, können Sie sagen#include <myheader.h> ob Sie GCC mit dem Flag aufgerufen haben -I .(was darauf hinweist, dass im aktuellen Verzeichnis nach Includes gesucht werden soll).

Ohne das -IFlag müssen Sie #include "myheader.h"die Datei einschließen oder myheader.hin das includeVerzeichnis Ihres Compilers wechseln .

Adrian
quelle
22

Standardmäßig - ja, sie sind unterschiedlich:

  • Eine Vorverarbeitungsanweisung des Formulars

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

    Durchsucht eine Folge von implementierungsdefinierten Stellen nach einem Header, der durch die angegebene Reihenfolge zwischen dem <und den >Trennzeichen eindeutig identifiziert wird , und ersetzt diese Anweisung durch den gesamten Inhalt des Headers. Wie die Orte angegeben oder der Header identifiziert werden, ist implementierungsdefiniert.

  • Eine Vorverarbeitungsanweisung des Formulars

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

    bewirkt, dass diese Anweisung durch den gesamten Inhalt der Quelldatei ersetzt wird, der durch die angegebene Reihenfolge zwischen den "Trennzeichen gekennzeichnet ist. Die benannte Quelldatei wird implementierungsdefiniert gesucht. Wenn diese Suche nicht unterstützt wird oder wenn die Suche fehlschlägt, wird die Anweisung erneut verarbeitet, als ob sie gelesen würde

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

    mit der identischen enthaltenen Sequenz (einschließlich >Zeichen, falls vorhanden) aus der ursprünglichen Direktive.

  • Eine Vorverarbeitungsanweisung des Formulars

    #include pp-tokens new-line

    (das nicht mit einem der beiden vorherigen Formulare übereinstimmt) ist zulässig. Die Vorverarbeitungstoken nach includeder Direktive werden wie im normalen Text verarbeitet. (Jeder Bezeichner, der derzeit als Makroname definiert ist, wird durch seine Ersetzungsliste von Vorverarbeitungstoken ersetzt.) Die nach allen Ersetzungen resultierende Direktive muss mit einem der beiden vorherigen Formulare übereinstimmen. Die Methode, mit der eine Folge von Vorverarbeitungstoken zwischen einem <und einem >Vorverarbeitungstokenpaar oder einem "Zeichenpaar zu einem Vorverarbeitungstoken mit einem einzelnen Headernamen kombiniert wird, ist implementierungsdefiniert.

Definitionen:

  • h-char: Jedes Mitglied des Quellzeichensatzes mit Ausnahme des Zeilenumbruchs und >

  • q-char: Jedes Mitglied des Quellzeichensatzes mit Ausnahme des Zeilenumbruchs und "

Beachten Sie, dass der Standard keine Beziehung zwischen den implementierungsdefinierten Manieren feststellt. Das erste Formular sucht auf eine implementierungsdefinierte Weise und das andere auf eine (möglicherweise andere) implementierungsdefinierte Weise. Der Standard legt außerdem fest, dass bestimmte Include-Dateien vorhanden sein müssen (z. B. <stdio.h>).

Formal müssten Sie das Handbuch für Ihren Compiler lesen, aber normalerweise #include "..."durchsucht das Formular (traditionell) das Verzeichnis der Datei, in der das #includezuerst gefunden wurde, und dann die Verzeichnisse, die das #include <...>Formular durchsucht (den Include-Pfad, z. B. Systemheader) ).

Himmel König
quelle
2
Dies ist meistens genau der gleiche Text wie die Antwort von piCookie aus sieben Jahren zuvor.
Kyle Strand
5
@KyleStrand Das liegt daran, dass derselbe Text ein Zitat des relevanten Abschnitts im Standard ist - dieser Text sollte identisch sein. Die eigentliche Antwort ist nicht derselbe Text und etwas anders - obwohl ich auch erkenne, dass sie in der Dokumentation für die Implementierung geschrieben wird, stelle ich auch fest, dass es auch eine traditionelle Art gibt, wie diese interpretiert werden (die meisten oder alle Compiler, die ich verwendet habe, respektieren). .
Skyking
2
IMO ist dies hier die beste Antwort, da sie sowohl das abdeckt, was der Standard sagt, als auch das, was die meisten Compiler tatsächlich tun.
Plugwash
17

Vielen Dank für die tollen Antworten, insb. Adam Stelmaszczyk und piCookie und aib.

Wie viele Programmierer habe ich die informelle Konvention verwendet, das "myApp.hpp"Formular für anwendungsspezifische Dateien und das <libHeader.hpp>Formular für Bibliotheks- und Compilersystemdateien zu verwenden, dh Dateien, die in /Iund angegeben sindINCLUDE jahrelang Umgebungsvariable angegeben sind, und dachte, dies sei der Standard.

Der C-Standard besagt jedoch, dass die Suchreihenfolge implementierungsspezifisch ist, was die Portabilität erschweren kann. Um die Sache noch schlimmer zu machen, verwenden wir Jam, der automatisch herausfindet, wo sich die Include-Dateien befinden. Sie können relative oder absolute Pfade für Ihre Include-Dateien verwenden. dh

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

Ältere Versionen von MSVS erforderten doppelte Backslashes (\\), aber das ist jetzt nicht erforderlich. Ich weiß nicht, wann es sich geändert hat. Verwenden Sie einfach Schrägstriche, um die Kompatibilität mit 'nix zu gewährleisten (Windows akzeptiert dies).

Wenn Sie sich darüber wirklich Sorgen machen, verwenden Sie"./myHeader.h" für eine Include-Datei im selben Verzeichnis wie der Quellcode (in meinem aktuellen, sehr großen Projekt sind einige doppelte Include-Dateinamen verstreut - wirklich ein Problem bei der Konfigurationsverwaltung).

Hier ist die MSDN-Erklärung, die hier zur Vereinfachung kopiert wurde.

Zitierte Form

Der Präprozessor sucht nach Include-Dateien in dieser Reihenfolge:

  1. Im selben Verzeichnis wie die Datei, die die Anweisung #include enthält.
  2. In den Verzeichnissen der aktuell geöffneten Include-Dateien in umgekehrter Reihenfolge, in der
    sie geöffnet wurden. Die Suche beginnt im Verzeichnis der übergeordneten Include-Datei und wird
    in den Verzeichnissen aller Großeltern-Include-Dateien nach oben fortgesetzt.
  3. Entlang des Pfades, der von jeder /ICompileroption angegeben wird .
  4. Entlang der Pfade, die von der INCLUDEUmgebungsvariablen angegeben werden.

Winkelklammerform

Der Präprozessor sucht nach Include-Dateien in dieser Reihenfolge:

  1. Entlang des von jedem angegebenen Pfades /ICompileroption .
  2. Wenn die Kompilierung in der Befehlszeile erfolgt, entlang der Pfade, die von der INCLUDEUmgebungsvariablen angegeben werden.
riderBill
quelle
16

Zumindest für die GCC-Version <= 3.0 generiert die spitze Klammerform keine Abhängigkeit zwischen der enthaltenen und der eingeschlossenen Datei.

Wenn Sie also Abhängigkeitsregeln generieren möchten (z. B. mit der Option GCC -M), müssen Sie das Anführungszeichen für die Dateien verwenden, die in den Abhängigkeitsbaum aufgenommen werden sollen.

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

Denis Ros
quelle
1
Ja, es gibt verschiedene Möglichkeiten, Abhängigkeiten zu generieren. Das ist einer von ihnen, aber es ist nicht der einzige.
Pryftan
15

Für #include ""einen Compiler sucht normalerweise den Ordner der Datei , die das beinhalten enthält und dann die anderen Ordner. Denn #include <>der Compiler durchsucht nicht den Ordner der aktuellen Datei.

Maxim Egorushkin
quelle
1
Ich bin mir nicht sicher, warum die Leute anderer Meinung sind.
Maxim Egorushkin
Ich vermute, das liegt daran, dass die meisten Leute nur die Dateien in ihrem CWD kompilieren. Wenn Sie sich im Verzeichnis foo befinden und foo / unittest / bar.c kompilieren und es bar.h enthält, funktioniert "bar.h" und <bar.h> nicht.
1
@ Maxim Leute sind anderer Meinung, weil das Verhalten, das Sie beschreiben, nicht Standard C ist.
Osvein
2
@Spookbuster Richtig, der Standard sagt beides <filename>und "filename"sucht nach implementierungsdefinierten Stellen.
Maxim Egorushkin
14

Wenn Sie #include <Dateiname> verwenden, sucht der Vorprozessor nach der Datei im Verzeichnis der C \ C ++ - Headerdateien (stdio.h \ cstdio, Zeichenfolge, Vektor usw.). Wenn Sie jedoch #include "Dateiname" verwenden: Zuerst sucht der Vorprozessor nach der Datei im aktuellen Verzeichnis, und wenn dies nicht der Fall ist, sucht er sie im Verzeichnis der C \ C ++ - Headerdateien.

Chayim Friedman
quelle
1
Nachdem jahrelang eine perfekte Antwort verfügbar war, warum eine einreichen, das ist einfach offensichtlich falsch? Obwohl allgemein üblich, #includebezieht sich die Richtlinie überhaupt nicht ausschließlich auf Dateien.
Unsichtbarer
@IInspectable bitte erklären Sie, warum es überhaupt nicht mit Dateien zusammenhängt.
Behrooz Karjoo
11

Ein #include mit spitzen Klammern durchsucht eine "implementierungsabhängige Liste von Stellen" (was eine sehr komplizierte Art ist, "Systemheader" zu sagen) nach der einzuschließenden Datei.

Ein #include mit Anführungszeichen sucht nur nach einer Datei (und "in implementierungsabhängiger Weise" bleh). Das heißt, im normalen Englisch wird versucht, den Pfad / Dateinamen anzuwenden, den Sie darauf werfen, und es wird kein Systempfad vorangestellt oder anderweitig manipuliert.

Wenn #include "" fehlschlägt, wird es vom Standard erneut als #include <> gelesen.

Die gcc-Dokumentation enthält eine (compilerspezifische) Beschreibung, die zwar spezifisch für gcc und nicht für den Standard ist, aber viel einfacher zu verstehen ist als die anwaltliche Rede über die ISO-Standards.

Damon
quelle
Die Verwendung von spitzen Klammern oder Anführungszeichen hat jedoch keinen Einfluss auf die Art und Weise, wie die Dateien enthalten sind. Dies ist genau das Gleiche: Der Präprozessor erstellt im Wesentlichen eine große Quelldatei, indem er den Code von Include-Dateien in die ursprüngliche Quelldatei kopiert und vor dem Geben kopiert es an den Compiler (Präprozessor macht andere Dinge, wie #define Sustitution, #if Evaluation, aber die #
Include-
Was ist mit Konflikten? Angenommen, ich habe zlib.hin meinen 'Benutzer'-Suchpfaden eine andere Version im Systemsuchpfad. Enthält dann #include <zlib.h>die Systemversion und #include "zlib.h"meine eigene?
the_mandrill
Aha, beantwortete meine eigene Frage: stackoverflow.com/questions/21593/…
the_mandrill
Vielen Dank, dass Sie anerkannt haben, dass sowohl die Standards als auch die typischen Implementierungskonventionen hier relevant sind, anstatt lediglich anzugeben, dass sie nicht erkennbar sind, weil sie nicht im Standard festgelegt sind.
Kyle Strand
10
#include "filename" // User defined header
#include <filename> // Standard library header.

Beispiel:

Der Dateiname hier ist 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

In der Klassenimplementierung (z. B. Seller.cppund in anderen Dateien, die die Datei verwenden Seller.h) sollte der vom Benutzer definierte Header nun wie folgt enthalten sein:

#include "Seller.h"
Barbara
quelle
10
  • #include <> ist für vordefinierte Header-Dateien

Wenn die Header-Datei vordefiniert ist, schreiben Sie einfach den Namen der Header-Datei in eckige Klammern und es sieht folgendermaßen aus (vorausgesetzt, wir haben einen vordefinierten Header-Dateinamen iostream):

#include <iostream>
  • #include " " ist für Header-Dateien, die der Programmierer definiert

Wenn Sie (der Programmierer) Ihre eigene Header-Datei geschrieben haben, würden Sie den Namen der Header-Datei in Anführungszeichen schreiben. Angenommen, Sie haben eine Header-Datei mit dem Namen geschrieben myfile.h. Dies ist ein Beispiel dafür, wie Sie die include-Direktive verwenden würden, um diese Datei einzuschließen:

#include "myfile.h"
VishalSoni
quelle
2
Es hat überhaupt nichts mit vordefinierten Header-Dateien zu tun. Es hat mit Orten zu tun, nach denen gesucht werden muss.
C Johnson
9

Viele der Antworten hier konzentrieren sich auf die Pfade, die der Compiler durchsucht, um die Datei zu finden. Während dies bei den meisten Compilern der Fall ist, darf ein konformer Compiler mit den Auswirkungen der Standardheader vorprogrammiert werden und #include <list>beispielsweise als Schalter behandelt werden, und er muss überhaupt nicht als Datei vorhanden sein.

Dies ist nicht rein hypothetisch. Es gibt mindestens einen Compiler, der so funktioniert. Die Verwendung #include <xxx>nur mit Standard-Headern wird empfohlen.

sp2danny
quelle
9
#include <abc.h>

wird verwendet, um Standardbibliotheksdateien einzuschließen. Der Compiler überprüft also die Speicherorte, an denen sich Standardbibliotheksheader befinden.

#include "xyz.h"

weist den Compiler an, benutzerdefinierte Header-Dateien einzuschließen. Der Compiler sucht also im aktuellen Ordner oder in den -Idefinierten Ordnern nach diesen Header-Dateien .

Christy Wald
quelle
7

Fügen Sie in C ++ eine Datei auf zwei Arten hinzu:

Das erste ist #include, das den Präprozessor anweist, nach der Datei am vordefinierten Standardspeicherort zu suchen. Dieser Speicherort ist häufig eine INCLUDE-Umgebungsvariable, die den Pfad zum Einschließen von Dateien angibt.

Der zweite Typ ist #include "Dateiname", der den Präprozessor anweist, zuerst nach der Datei im aktuellen Verzeichnis und dann an den vordefinierten Speicherorten zu suchen, die der Benutzer eingerichtet hat.

virat
quelle
7

Formular 1 - #include <xxx>

Sucht zunächst nach dem Vorhandensein einer Header-Datei im aktuellen Verzeichnis, von dem aus die Direktive aufgerufen wird. Wird es nicht gefunden, wird in der vorkonfigurierten Liste der Standardsystemverzeichnisse gesucht.

Formular 2 - #include "xxx"

Dies sucht nach dem Vorhandensein einer Header-Datei im aktuellen Verzeichnis, von dem aus die Direktive aufgerufen wird.


Die genaue Liste der Suchverzeichnisse hängt vom Zielsystem ab, davon, wie GCC konfiguriert ist und wo es installiert ist. Sie finden die Suchverzeichnisliste Ihres GCC-Compilers, indem Sie sie mit der Option -v ausführen.

Sie können dem Suchpfad zusätzliche Verzeichnisse hinzufügen, indem Sie - I dir verwenden . Dadurch wird dir nach dem aktuellen Verzeichnis (für die Anführungszeichenform der Direktive) und vor den Standardsystemverzeichnissen durchsucht.


Grundsätzlich ist die Form "xxx" nichts anderes als die Suche im aktuellen Verzeichnis; Wenn nicht gefunden, fällt das Formular zurück

Darshan L.
quelle
3
Wenn Sie sich entscheiden, eine ältere Frage zu beantworten, die gut etablierte und korrekte Antworten enthält, erhalten Sie möglicherweise keine Gutschrift, wenn Sie spät am Tag eine neue Antwort hinzufügen. Wenn Sie einige unverwechselbare neue Informationen haben oder davon überzeugt sind, dass die anderen Antworten alle falsch sind, fügen Sie auf jeden Fall eine neue Antwort hinzu, aber "noch eine Antwort", die die gleichen grundlegenden Informationen lange nach dem Stellen der Frage enthält, ist normalerweise gewonnen. " Ich verdiene dir nicht viel Kredit.
Jonathan Leffler
1
@ Jonathan Leffler Können Sie mich auf die "gut etablierte" Antwort verweisen, die Ihrer Meinung nach genauso präzise und genau ist wie Darshans Antwort?
personal_cloud
1
Die Beschreibung des #include "header.h"Formulars ist nicht korrekt, @personal_cloud. Ich halte die Antwort von piCookie und Yann Droneaud für am relevantesten, da sie identifizieren, woher ihre Informationen stammen. Ich finde die am besten gewählte Antwort auch nicht ganz zufriedenstellend.
Jonathan Leffler
Warum wird diese Antwort oben angezeigt, während zwei Antworten weiter unten mehr als 650 Stimmen haben? Diese Antwort hat mich verwirrt, weil sie nicht dem von mir beobachteten Verhalten entspricht. Dies kann daran liegen, dass der letzte Satz unterbrochen ist, weil die spitzen Klammern nicht entkommen. Ich bin mir nicht sicher, was es bedeuten soll.
Neonit
6

Das #include <filename>wird verwendet, wenn auf eine Systemdatei verwiesen wird. Dies ist eine Header-Datei, die sich an Standardspeicherorten des Systems wie /usr/includeoder befindet /usr/local/include. Für Ihre eigenen Dateien, die in einem anderen Programm enthalten sein müssen, müssen Sie die #include "filename"Syntax verwenden.

srsci
quelle
6

Der "<Dateiname>" sucht in Standardspeicherorten der C-Bibliothek

Während "Dateiname" auch im aktuellen Verzeichnis sucht.

Idealerweise verwenden Sie <...> für Standard-C-Bibliotheken und "..." für Bibliotheken, die Sie schreiben und die im aktuellen Verzeichnis vorhanden sind.

Jigar Karangiya
quelle
4
Welche neuen Informationen fügen diese Antwort zu den anderen hinzu?
Daniel Langr
5

Die einfache allgemeine Regel besteht darin, spitze Klammern zu verwenden, um Header-Dateien einzuschließen, die mit dem Compiler geliefert werden. Verwenden Sie doppelte Anführungszeichen, um andere Header-Dateien einzuschließen. Die meisten Compiler machen das so.

1.9 - Header-Dateien erläutern ausführlicher die Anweisungen vor dem Prozessor. Wenn Sie ein Anfänger sind, sollte diese Seite Ihnen helfen, all das zu verstehen. Ich habe es von hier gelernt und habe es bei der Arbeit verfolgt.

Eakan Gopalakrishnan
quelle
4
#include <filename>

wird verwendet, wenn Sie die Header-Datei des C / C ++ - Systems oder der Compiler-Bibliotheken verwenden möchten. Diese Bibliotheken können stdio.h, string.h, math.h usw. sein.

#include "path-to-file/filename"

wird verwendet, wenn Sie Ihre eigene benutzerdefinierte Header-Datei verwenden möchten, die sich in Ihrem Projektordner oder an einer anderen Stelle befindet.

Weitere Informationen zu Präprozessoren und Headern. Lesen Sie C - Präprozessoren .

Hafiz Shehbaz Ali
quelle
3

#include <filename>

  • Der Präprozessor sucht implementierungsabhängig. Es weist den Compiler an, das Verzeichnis zu durchsuchen, in dem sich die Systemheaderdateien befinden.
  • Diese Methode wird normalerweise verwendet, um Standard-Header-Dateien zu finden.

#include "filename"

  • Dies weist den Compiler an, Header-Dateien zu durchsuchen, in denen das Programm ausgeführt wird. Wenn es fehlgeschlagen ist, verhält es sich wie#include <filename> und durchsucht die Header-Datei dort, wo die System-Header-Dateien gespeichert sind.
  • Diese Methode wird normalerweise zum Identifizieren benutzerdefinierter Header-Dateien (Header-Dateien, die vom Benutzer erstellt werden) verwendet. Verwenden Sie dies daher nicht, wenn Sie die Standardbibliothek aufrufen möchten, da dies mehr Kompilierungszeit als benötigt #include <filename>.
Kalana
quelle
2

Um die Suchreihenfolge auf Ihrem System mit gcc basierend auf der aktuellen Konfiguration anzuzeigen, können Sie den folgenden Befehl ausführen. Weitere Details zu diesem Befehl finden Sie hier

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

Apple LLVM Version 10.0.0 (clang-1000.10.44.2)
Ziel: x86_64-apple-darwin18.0.0
Thread-Modell: posix InstalledDir: Library / Developer / CommandLineTools / usr / bin
"/ Library / Developer / CommandLineTools / usr / bin / clang" -cc1 -triple x86_64-apple-macosx10.14.0 -Wdeprecated-objc-isa-usage -Werror = veraltet-objc-isa-usage -E -disable-free - disable-llvm-verifier -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-erweiterte-Block-Signatur -fobjc-Laufzeit = macosx-10.14.0 -fmax-type-align = 16 -fdiagnostics-show-option -fcolor-diagnostics -traditional-cpp -o - -xc / dev / null
clang -cc1 Version 10.0.0 (clang-1000.10.44.2) Standardziel x86_64-apple-darwin18.0.0 ignoriert nicht vorhandenes Verzeichnis "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/local/include" ignoriert nicht vorhandenes Verzeichnis "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/Library/Frameworks"
#include "..." Die Suche beginnt hier:
#include <...> Die Suche beginnt hier:
/ usr / local / include
/ Bibliothek / Entwickler / CommandLineTools / usr / lib / clang / 10.0.0 / include
/ Bibliothek / Entwickler / CommandLineTools / usr / include
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include
/ Library / Developer / CommandLineTools / SDKs / MacOSX10.14.sdk / System / Library / Frameworks (Framework-Verzeichnis)
Ende der Suchliste.

Hogstrom
quelle
1
#include <file> 

Schließt eine Datei ein, in der das Standardverschlussverzeichnis enthalten ist.

#include "file" 

Schließt eine Datei in das aktuelle Verzeichnis ein, in dem sie kompiliert wurde.

IAmAUser
quelle
-2

Es gibt zwei Möglichkeiten, eine # include-Anweisung zu schreiben. Dies sind:

#include"filename"
#include<filename>

Die Bedeutung jeder Form ist

#include"mylib.h"

Dieser Befehl sucht nach der Datei mylib.him aktuellen Verzeichnis sowie nach der angegebenen Liste von Verzeichnissen, wie im Include-Suchpfad angegeben, der möglicherweise eingerichtet wurde.

#include<mylib.h>

Dieser Befehl sucht mylib.hnur in der angegebenen Liste von Verzeichnissen nach der Datei .

Der Include-Suchpfad ist nichts anderes als eine Liste von Verzeichnissen, die nach der enthaltenen Datei durchsucht werden sollen. Mit verschiedenen C-Compilern können Sie den Suchpfad auf verschiedene Arten festlegen.

Noshiii
quelle
1
Wenn Sie sich entscheiden, eine ältere Frage zu beantworten, die gut etablierte und korrekte Antworten enthält, erhalten Sie möglicherweise keine Gutschrift, wenn Sie spät am Tag eine neue Antwort hinzufügen. Wenn Sie einige unverwechselbare neue Informationen haben oder davon überzeugt sind, dass die anderen Antworten alle falsch sind, fügen Sie auf jeden Fall eine neue Antwort hinzu, aber "noch eine Antwort", die die gleichen grundlegenden Informationen lange nach dem Stellen der Frage enthält, ist normalerweise gewonnen. " Ich verdiene dir nicht viel Kredit.
Jonathan Leffler