Wie verwende ich die #include-Direktive richtig?

Lesezeit: 7 Minuten

Benutzer-Avatar
HauptID

Gibt es Material zur Verwendung #include korrekt? Ich habe kein C/C++-Lehrbuch gefunden, das diese Verwendung im Detail erklärt. Bei formalen Projekten bin ich immer verwirrt, wenn ich damit umgehe.

Benutzer-Avatar
Ausgaben

Der große, der mich immer zum Stolpern gebracht hat, war dieser:

Dies sucht im Header-Pfad:

#include <stdio.h>

Dies sucht in Ihrem lokalen Verzeichnis:

#include "myfile.h"

Das Zweite, was Sie mit JEDEM Header tun sollten, ist Folgendes:

meindateiname.h:

#ifndef MYFILENAME_H
#define MYFILENAME_H
//put code here
#endif

Dieses Muster bedeutet, dass Sie nicht auf die Neudefinition der Header in Ihrer Zusammenstellung verzichten können (ein Hoch auf orsogufo für den Hinweis, dass dies als “include guard” bezeichnet wird). Lesen Sie etwas darüber, wie der C-Compiler die Dateien tatsächlich kompiliert (vor dem Linken), da dies die Welt von #define und #include für Sie sehr sinnvoll machen wird, der C-Compiler, wenn es um das Parsen von Text geht, ist nicht sehr gut intelligent. (Der C-Compiler selbst ist jedoch eine andere Sache)

  • Das Muster heißt “include guard”.

    – Paolo Tedesco

    21. Januar 2009 um 9:35 Uhr

  • Und die meisten Compiler erlauben die #pragma once gleichwertig

    – xtofl

    21. Januar 2009 um 10:34 Uhr

  • @xtofi: Nein, tun sie nicht. Das ist eine MS-Erweiterung. Nur sehr wenige andere Compiler unterstützen es.

    – Martin York

    21. Januar 2009 um 12:38 Uhr

  • @Spence: Nein, das ist nicht richtig. Das zweite Include durchsucht auch eine Reihe von Verzeichnissen (nur eine andere Gruppe)

    – Martin York

    21. Januar 2009 um 12:41 Uhr

  • Martin hat Recht. der Unterschied zwischen “” und <> ist nicht sicher. Die Implementierung definiert, was dieser Unterschied ist. Die meisten Compiler sehen jedoch zuerst in den dateirelativen Pfad, wenn “” verwendet wird.

    – Johannes Schaub – litb

    21. Januar 2009 um 22:20 Uhr

  • Sehen Sie sich Large-Scale C++ Software Design von John Lakos an, wenn Sie das Geld haben.
  • Die Google C++-Codierungsrichtlinien enthalten auch einige OK-Sachen.
  • Sehen Sie sich auch die Materialien von Sutter Herb online (Blog) an.

Grundsätzlich müssen Sie verstehen, wo Include-Header NICHT erforderlich sind, z. Vorwärtserklärung. Versuchen Sie auch sicherzustellen, dass Include-Dateien nacheinander kompiliert werden, und fügen Sie #includes nur dann in h-Dateien ein, wenn dies unbedingt erforderlich ist (z. B. Vorlagen).

  • Ich denke, das, worüber Sie gesprochen haben, ist das, was ich brauche. Die oben genannten Dinge sind einfach genug, damit jeder es weiß.

    – HauptID

    21. Januar 2009 um 10:06 Uhr

Benutzer-Avatar
Martin York

Ihr Compiler unterstützt also möglicherweise zwei eindeutige Suchpfade für Include-Dateien:
Informell könnten wir den System-Include-Pfad und den Benutzer-Include-Pfad nennen.
Das #Enthalten Sie sucht den System-Include-Pfad.
Das #geben Sie “XX” ein durchsucht den Benutzer-Include-Pfad und dann den System-Include-Pfad.

Überprüfung des Normentwurfs n2521:
Abschnitt 16.2:

2 A preprocessing directive of the form 

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

  searches a sequence of implementation-defined places for a header identified
  uniquely by the specified sequence between the < and > delimiters, and
  causes the replacement of that directive by the entire contents of the
  header. How the places are specified or the header identified is
  implementation-defined. 

3 A preprocessing directive of the form 

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

  causes the replacement of that directive by the entire contents of the
  source file identified by the specified sequence between the " " delimiters.
  The named source file is searched for in an implementation-defined manner.
  If this search is not supported, or if the search fails, the directive is
  reprocessed as if it read

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

  with the identical contained sequence (including > characters, if any)
  from the original directive. 

Ein Beispiel hierfür wäre gcc

  -isystem <dir>              Add <dir> to the start of the system include path
  -idirafter <dir>            Add <dir> to the end of the system include path
  -iwithprefix <dir>          Add <dir> to the end of the system include path
  -iquote <dir>               Add <dir> to the end of the quote include path
  -iwithprefixbefore <dir>    Add <dir> to the end of the main include path
  -I <dir>                    Add <dir> to the end of the main include path

Um zu sehen, wo Ihr gcc sucht, gehen Sie wie folgt vor:

g++ -v -E -xc++ /dev/null -I LOOK_IN_HERE
#include "..." search starts here:
#include <...> search starts here:
  LOOK_IN_HERE
  /usr/include/c++/4.0.0
  /usr/include/c++/4.0.0/i686-apple-darwin9
  /usr/include/c++/4.0.0/backward
  /usr/local/include
  /usr/lib/gcc/i686-apple-darwin9/4.0.1/include
  /usr/include
  /System/Library/Frameworks (framework directory)
  /Library/Frameworks (framework directory)
End of search list.

Wie nutzen Sie dieses Wissen?
Es gibt mehrere Denkschulen. Aber ich führe meine Bibliotheken immer von den spezifischsten bis zu den allgemeinsten auf.

Beispiel

Datei: plop.cpp

#include "plop.h"
#include "plop-used-class.h"

/// C Header Files
#include <stdio.h>    // I know bad example but I drew a blank

/// C++ Header files
#include <vector>
#include <memory>

Wenn also die Header-Datei “plop-used-class.h” enthalten haben sollte, wird dies vom Compiler erkannt. Wenn ich den ganz oben gesetzt hätte, wäre dieser Fehler vor dem Compiler verborgen gewesen.

  • … welche Compiler unterstützen die Systempfad vs. Benutzerpfad Unterscheidung? Anscheinend beziehen Sie sich hier ausschließlich auf GCC …

    – Wolf

    12. Dezember 2017 um 14:48 Uhr


  • @Wolf Ich habe den Standard zitiert (wie er 09 war). Was sagt, wie die Datei gefunden wird implementation-defined. Ich zeige dann die gcc-Implementierung als “Beispiel” (gcc ist der vorherrschende C++-Compiler zu der Zeit, clang ist da, aber in 09 kaum verwendbar, bis 2011 nicht relevant, MS cl-Compiler scheint nur einen einzigen Suchpfad zu haben).

    – Martin York

    12. Dezember 2017 um 17:05 Uhr


  • Ich verstehe, danke. Sie haben also übersetzt implementierungsdefinierte Orte hinein System-Include-Pfad.

    – Wolf

    12. Dezember 2017 um 17:12 Uhr

  • @Wolf Zusätzlich zur genauen Beantwortung der Frage mit einem Zitat aus dem Standard. Ich habe dann ein reales Beispiel dafür illustriert, wie eine Implementierung interpretiert wird implementation-defined um eine reale Situation zu lösen.

    – Martin York

    12. Dezember 2017 um 18:56 Uhr

Denken Sie zusätzlich zu den anderen Kommentaren daran, dass Sie keinen Header in einen anderen Header #einschließen müssen, wenn Sie nur einen Zeiger oder eine Referenz haben. Z.B:

Kopfzeile erforderlich:

#include "Y.h"
class X
{
   Y y; // need header for Y
};

Überschrift nicht erforderlich:

class Y; 
class X
{
   Y* y; // don't need header for Y
};
//#include "Y.h" in .cpp file

Das zweite Beispiel wird schneller kompiliert und hat weniger Abhängigkeiten. Dies kann in großen Codebasen wichtig sein.

Nur eine Ergänzung zu Andy Brices Antwort, Sie können auch mit Vorwärtsdeklarationen für Funktionsrückgabewerte auskommen:

class Question;
class Answer;

class UniversityChallenge
{
...
    Answer AskQuestion( Question* );
...
};

Hier ist ein Link zu einer Frage, die ich vor einiger Zeit mit einigen guten Antworten gestellt habe http://bytes.com/groups/c/606466-forward-declaration-allowed.

Benutzer-Avatar
Yuval F

Header-Dateien sind die Methode von C, Schnittstelle und Implementierung zu trennen. Sie werden in zwei Typen unterteilt: Standard- und benutzerdefinierte Header-Dateien. Eine Standard-Header-Datei wie string.h ermöglicht uns den Zugriff auf die Funktionalität einer zugrunde liegenden C-Bibliothek. Sie sollten es in jede .c-Datei einfügen, die die entsprechende Funktionalität verwendet. Normalerweise werden dabei Klammern wie in #include verwendet. Eine benutzerdefinierte Header-Datei legt Ihre Implementierung von Funktionen anderen Programmierern oder anderen Teilen Ihres C-Codes offen. Wenn Sie ein Modul namens rational.c für Berechnungen mit rationalen Zahlen implementiert haben, sollte es eine entsprechende rational.h-Datei für seine öffentliche Schnittstelle haben. Jede Datei, die die Funktionalität verwendet, sollte rational.h enthalten, und auch rational.c sollte sie enthalten. Normalerweise geschieht dies mit #include “rational.h”. Der Teil der Kompilierung, der die #includes ausführt, heißt the C-Präprozessor. Es führt hauptsächlich Textersetzungen durch und fügt Text ein. Spence hat Recht mit seinem Muster, doppelte #includes zu verhindern, die den Namensraum durcheinanderbringen. Dies ist die Basis der Inklusion, GNU-Make gibt dir viel mehr Kraft und auch viel mehr Ärger.

Benutzer-Avatar
Gemeinschaft

Sehen Sie sich die Diskussion zur Verwendung an #include<filename.h>
und #include<filename> für C++ enthält C-Bibliotheken.

1225470cookie-checkWie verwende ich die #include-Direktive richtig?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy