<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=83.64.199.107</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=83.64.199.107"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/83.64.199.107"/>
	<updated>2026-04-10T21:36:42Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Include-Files_(C)&amp;diff=14276</id>
		<title>Include-Files (C)</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Include-Files_(C)&amp;diff=14276"/>
		<updated>2004-08-29T18:22:50Z</updated>

		<summary type="html">&lt;p&gt;83.64.199.107: /* Problemlösung mit Makros */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Include-Files in C/C++ enthalten typischerweise Informationen, die im Rahmen der Kompilierung verschiedener anderer Quelltexte (mehrfach) benötigt werden.&lt;br /&gt;
&lt;br /&gt;
Wer bisher hauptsächlich kleinere (Assembler-) Programme für Mikrocontroller realisiert hat und sich nun langsam an größere Projekte heranwagt und deshalb auf C umsteigt, ist gut beraten, die Möglichkeiten sinnvoll einzusetzen, die Include-Files in C bieten. Dabei gilt es allerdings auch, einige Fallgruben zu vermeiden - mehr dazu in diesem Artikel.&lt;br /&gt;
&lt;br /&gt;
== Verwendung von Include-Files ==&lt;br /&gt;
&lt;br /&gt;
Die Verwendung von Include-Files in [[C]] und [[C-Plusplus|C++]] führt in der Regel zu besser strukturierten und damit besser wartbaren Programmen. Indem bestimmte, zentrale Informationen nur ein einziges Mal hinterlegt werden, fällt insbesondere bei Änderungen weniger Aufwand an.&lt;br /&gt;
&lt;br /&gt;
Der übliche Suffix für Include-Files ist &amp;quot;&amp;lt;tt&amp;gt;.h&amp;lt;/tt&amp;gt;&amp;quot;, manchmal auch &amp;quot;&amp;lt;tt&amp;gt;.hpp&amp;lt;/tt&amp;gt;&amp;quot; (für C++), und die &#039;&#039;Verwendung&#039;&#039; eines Include-Files ist sehr einfach:&lt;br /&gt;
 #include &amp;quot;xyz.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Wird der Dateiname in spitze Klammern gesetzt, dann sucht der Präprozessor die Datei nicht im aktuellen Verzeichnis, sondern im Standard-Include-Pfad des Compilers:&lt;br /&gt;
 #include &amp;lt;io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei sind auch relative Verzeichnisangaben erlaubt:&lt;br /&gt;
 #include &amp;lt;avr/timer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Probleme bei Include-Files ==&lt;br /&gt;
In Include-Files werden mitunter Informationen aus anderen Include-Files benötigt und es ist an der Verwendungsstelle eines Include-Files oft nicht das Wissen über die möglicherweise sehr komplexen Abhängigkeiten vorhanden. Nachfolgend wird ausgehend von einer typischen Problemstellung eine Standardtechnik erläutert, die hilft, das Wissen um Abhängigkeiten an der Verwendungsstelle überflüssig zu machen:&lt;br /&gt;
&lt;br /&gt;
Angenommen, es existieren zwei Datenstrukturen für die es die Typdefinitionen &amp;lt;tt&amp;gt;s1_t&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;s2_t&amp;lt;/tt&amp;gt; gibt, die jeweils entsprechenden Include-Files hinterlegt sind, also&lt;br /&gt;
&amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* Definition der Datenstruktur s1 */&lt;br /&gt;
struct s1 {&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
typedef struct s1 s1_t;&lt;br /&gt;
...&lt;br /&gt;
/* Funktions-Deklarationen */&lt;br /&gt;
void foo(s1_t);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Datei &amp;lt;tt&amp;gt;s2.h&amp;lt;/tt&amp;gt; sieht so aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* Definition der Datenstruktur s2 */&lt;br /&gt;
struct s2 {&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
typedef struct s2 s2_t;&lt;br /&gt;
...&lt;br /&gt;
/* Funktions-Deklarationen */&lt;br /&gt;
s2_t *bar();&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine bestimmte Applikation benötigt nun beide Struktur- und Funktions-Definitionen und inkludiert entsprechend beide Dateien, es gibt also eine kompilierbare Datei (z.B. &amp;lt;tt&amp;gt;main.c&amp;lt;/tt&amp;gt;) die wie folgt aussieht:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;quot;s1.h&amp;quot;&lt;br /&gt;
#include &amp;quot;s2.h&amp;quot;&lt;br /&gt;
...&lt;br /&gt;
int main() {&lt;br /&gt;
    s1_t a;&lt;br /&gt;
    s2_t *b;&lt;br /&gt;
    ...&lt;br /&gt;
    foo(a);&lt;br /&gt;
    b = bar();&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
So weit, so gut.&lt;br /&gt;
&lt;br /&gt;
Nun kommt es eines Tages zu einer Änderung, die darauf hinausläuft, dass die erste Struktur die zweite als Element enthält. Das heißt die Datei &amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt; sieht nun wie folgt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct s1 {&lt;br /&gt;
    s2_t x;&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
...&lt;br /&gt;
/* Funktions-Deklarationen */&lt;br /&gt;
void foo(s2_t);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Daraufhin wird sich &amp;lt;tt&amp;gt;main.c&amp;lt;/tt&amp;gt;(!) nicht mehr kompilieren lassen, da bei der Verarbeitung von &amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt; (noch) nicht bekannt ist, worum es sich um bei &amp;lt;tt&amp;gt;s2_t&amp;lt;/tt&amp;gt; handelt. (Es könnte ja auch einfach nur ein Tippfehler sein!)&lt;br /&gt;
&lt;br /&gt;
Da es in der Praxis einen immensen Pflegeaufwand auslösen kann, wenn Änderungen in Include-Files Änderungen in vielen weiteren Dateien erfordern (dem Wesen nach soll ja eine Include-Dateien eine Information zentral für viele andere Dateien bereitstellen), muss nach einem Ausweg gesucht werden.&lt;br /&gt;
&lt;br /&gt;
Dieser könnte so aussehen, dass man &amp;quot;vorsorglich&amp;quot; die Beschreibung der verwendeten Datenstruktur in &amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt; inkludiert:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;quot;s2.h&amp;quot;&lt;br /&gt;
struct s1 {&lt;br /&gt;
    s2_t x;&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
...&lt;br /&gt;
/* Funktions-Deklarationen */&lt;br /&gt;
void foo(s2_t);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inkludiert das Hauptprogramm lediglich &amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt;, wäre nun alles in Ordnung, wenn aber beide Dateien inkludiert werden, beschwert sich der Compiler über die doppelte Definition der Datentypen. (Die doppelte Deklaration von Funktionen ist kein Fehler, wenn sie übereinstimmend erfolgt.)&lt;br /&gt;
&lt;br /&gt;
== Problemlösung mit Makros ==&lt;br /&gt;
Die übliche und - fast - perfekte Lösung des Problems besteht darin, den eigentlichen Inhalt eines Include-Files vor einer zweiten Verarbeitung durch eine &#039;&#039;bedingte Kompilierung&#039;&#039; zu schützen.&lt;br /&gt;
Bei der bedingten Kopilierung handelt es sich ebenfalls um ein Feature des [[C-Präprozessor]]s und es wird hier wie folgt auf die Datei &amp;lt;tt&amp;gt;s2.h&amp;lt;/tt&amp;gt; angewendet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef S2_h&lt;br /&gt;
#define S2_h&lt;br /&gt;
struct s2 {&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
...&lt;br /&gt;
/* Funktions-Deklarationen */&lt;br /&gt;
s2_t *bar();&lt;br /&gt;
...&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Da das beschriebene Problem in größeren Programmsystemen auch in Bezug auf die andere Struktur auftreten könnte, sollte man die Datei &amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt; vorsorglich mit einem ähnlichen Schutz ausstatten:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef S1_h&lt;br /&gt;
#define S1_h&lt;br /&gt;
#include &amp;quot;s2.h&amp;quot;&lt;br /&gt;
struct s1 {&lt;br /&gt;
    s2_t x;&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
...&lt;br /&gt;
/* Funktions-Deklarationen */&lt;br /&gt;
void foo(s2_t);&lt;br /&gt;
...&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Der nette Nebeneffekt ist, dass es damit auch keine Rolle spielt, in welcher Reihenfolge beide Dateien in &amp;lt;tt&amp;gt;main.cpp&amp;lt;/tt&amp;gt; inkludiert werden.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung der Regeln ==&lt;br /&gt;
Kochrezeptartig kann man beim Schreiben und Verwenden von Include-Files auch einfach die folgenden Regeln anwenden:&lt;br /&gt;
* Wird die externe Schnittstelle (Datenstrukturen, Funktions-Deklarationen) eines Moduls &#039;&#039;XYZ&#039;&#039; in einem Include-File &amp;lt;tt&amp;gt;xyz.h&amp;lt;/tt&amp;gt; beschrieben, so sollte ein bestimmter Makroname (z.B. &amp;lt;tt&amp;gt;XYZ_h&amp;lt;/tt&amp;gt;) für die Steuerung der tatsächlichen Verarbeitung des Include-Files reserviert werden(*1).&lt;br /&gt;
* Der Include-File selbst testet (und definiert anschließend) diesen Makro, um so eine doppelte Verarbeitung zu vermeiden.&lt;br /&gt;
* Wird in einer Kompilierung das Modul &#039;&#039;XYZ&#039;&#039; verwendet (= eine seiner Datenstrukturen oder Funktionen), wird auch der Include-File &amp;lt;tt&amp;gt;xyz.h&amp;lt;/tt&amp;gt; in diese Kompilierung eingeschlossen.&lt;br /&gt;
* Verwendet das Modul &#039;&#039;XYZ&#039;&#039; &#039;&#039;&#039;intern&#039;&#039;&#039; ein weiteres Modul &#039;&#039;UVW&#039;&#039;, so wird &#039;&#039;&#039;dessen&#039;&#039;&#039; Include-File &amp;lt;tt&amp;gt;uvw.h&amp;lt;/tt&amp;gt; im Include-File &amp;lt;tt&amp;gt;xyz.h&amp;lt;/tt&amp;gt; eingeschlossen.&lt;br /&gt;
&lt;br /&gt;
Die beschriebenen Regeln funktionieren zufriedenstellend und entlasten vor allem Programm-Code, welcher Include-Files lediglich einschließt, vom Wissen über komplexe Zusammenhänge zwischen einzelnen Modulen. Ferner spielt die Reihenfolge, in der man Include-Files verwendet, keine Rolle und man kann sie beliebig gruppieren und ordnen, so wie es am übersichtlichsten ist(*2).&lt;br /&gt;
&lt;br /&gt;
== Gegenseitige Bezugnahme ==&lt;br /&gt;
Eine Ausnahme von der allgemeinen Regel liegt vor, wenn sich zwei Datenstrukturen gegenseitig verwenden (was nur über Zeiger der Fall sein kann).&lt;br /&gt;
Alle wie auch immer gearteten Versuche, diese beiden Strukturdefinitionen und Funktionsprototypen in zwei verschiedene Include-Files aufzuteilen, also z.B. &amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef S1_h&lt;br /&gt;
#define S1_h&lt;br /&gt;
#include &amp;quot;s2.h&amp;quot;&lt;br /&gt;
struct s1 {&lt;br /&gt;
    struct s2 *px;&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
typedef struct s1 s1_t;&lt;br /&gt;
...&lt;br /&gt;
s2_t *bar(s1_t);&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
und &amp;lt;tt&amp;gt;s2.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef S2_h&lt;br /&gt;
#define S2_h&lt;br /&gt;
#include &amp;quot;s1.h&amp;quot;&lt;br /&gt;
struct s2 {&lt;br /&gt;
    struct s1 *yp;&lt;br /&gt;
    ....&lt;br /&gt;
};&lt;br /&gt;
...&lt;br /&gt;
void foo(s2_t);&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
werden scheitern - mit und ohne dem beschriebenen Schutz vor doppelter Verarbeitung!&lt;br /&gt;
&lt;br /&gt;
Die pragmatische Lösung ist hier, alles in einem &#039;&#039;&#039;gemeinsamen&#039;&#039;&#039; Include-File &amp;lt;tt&amp;gt;s1_s2.h&amp;lt;/tt&amp;gt; zu hinterlegen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef S1_S2_h&lt;br /&gt;
#define S1_S2_h&lt;br /&gt;
struct s1 {&lt;br /&gt;
    struct s2 *px;&lt;br /&gt;
    ....&lt;br /&gt;
};&lt;br /&gt;
typedef struct s1 s1_t;&lt;br /&gt;
&lt;br /&gt;
struct s2 {&lt;br /&gt;
    struct s1 *yp;&lt;br /&gt;
    ....&lt;br /&gt;
};&lt;br /&gt;
typedef struct s2 s2_t;&lt;br /&gt;
...&lt;br /&gt;
void foo(s2_t);&lt;br /&gt;
s2_t *bar(s1_t);&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Das ist insofern sinnvoll, als ein Programm, welches die eine Struktur kennen muss, stets auch die andere benötigt. Die Aufteilung in zwei Include-Files würde also keinen echten Vorteil bringen.&lt;br /&gt;
&lt;br /&gt;
Eine Ausnahme kann lediglich gemacht werden, wenn auf die jeweils andere Struktur ausschließlich über Zeiger(*3) zugegriffen wird, dann sind auch zwei Include-Files möglich, nämlich &amp;lt;tt&amp;gt;s1.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef S1_h&lt;br /&gt;
#define S1_h&lt;br /&gt;
struct s2; /* Vorausdeklaration */&lt;br /&gt;
struct s1 {&lt;br /&gt;
    struct s2 *px;&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
typdef struct s1 s1_t;&lt;br /&gt;
...&lt;br /&gt;
struct s2 *bar(s1_t);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
und &amp;lt;tt&amp;gt;s2.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef S2_h&lt;br /&gt;
#define S2_h&lt;br /&gt;
struct s1; /* Vorausdeklaration */&lt;br /&gt;
struct s2 {&lt;br /&gt;
    struct s1 *py;&lt;br /&gt;
    ...&lt;br /&gt;
};&lt;br /&gt;
typdef struct s2 s2_t;&lt;br /&gt;
...&lt;br /&gt;
void bar(struct s1 *);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Anstatt den jeweils anderen Include-File einzuschließen, sind nun die oben gezeigten Vorausdeklarationen vorzumehmen. (Allerdings sind damit die Typdefinitionen &amp;lt;tt&amp;gt;s1_t&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;s2_t&amp;lt;/tt&amp;gt; nicht verfügbar, die Bezugnahme auf die jeweils andere Struktur kann nur über &amp;lt;tt&amp;gt;struct s1&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;struct s2&amp;lt;/tt&amp;gt; erfolgen.)&lt;br /&gt;
     &lt;br /&gt;
----&lt;br /&gt;
* 1: Die genaue Beziehung zwischen dem Makro-Namen und dem Modul- (oder Struktur-) Namen ist dabei nicht so bedeutend. Die übliche Konvention, solche &amp;quot;Steuer-Makros&amp;quot; mit &amp;quot;&amp;lt;tt&amp;gt;_h&amp;lt;/tt&amp;gt;&amp;quot; oder &amp;quot;&amp;lt;tt&amp;gt;_H&amp;lt;/tt&amp;gt;&amp;quot; zu beenden, soll nur helfen, &amp;quot;zufällige&amp;quot; Kollissionen mit Makros zu vermeiden, die einen anderen Zweck haben.&lt;br /&gt;
* 2: Eine alphabetische Sortierung ist z.B. hilfreich, um bei einem Kompilierfehler schnell überprüfen zu können, ob vielleicht nur ein bestimmter Include-File vergessen wurde.&lt;br /&gt;
* 3: Bei der Verwendunng von C++ gilt das zusätzlich für die Bezugnahme über Referenzen.&lt;/div&gt;</summary>
		<author><name>83.64.199.107</name></author>
	</entry>
</feed>