Präporozessor
-
Guten Tag.
Ich habe mir vor 2Monaten ein Buch namens C++ Primer(vierte Auflage) gekauft und dabei arbeitete ich es bis heute durch,schritt für schritt.Nun aber bin ich bei einem sehr eigenartigen Punkt angestoßen,andem ich eure Hilfe brauchen werde.
Damit gemeint war soetwas in der Art ...
#ifndef SALESITEM_H #define SALESITEM_H //... //.. //. //. //.. //... #endif-)Ich verstehe leider nicht den Sinn und Zweck dieser Beispieles

Was #ifndef SALESITEM_H ist oder bedeutet,weiss ich irgendwie nicht.
#define SALESITEM_H ist schon ein bisschen klarer geworden,dass man dabei etwas definiert.Und mit #endif gibt's auch keine Probleme,da es sicherlich heisst,dass dieser Schritt beendet wird.-)SALESITEM_H könnte aber auch SALESTEST_P heissen, oder?
Also was es bedeutet und wozu gut es ist,das würde ich gerne irgendwie herausfinden wollen

Tutorials und anderes Zeugs würde mich auch erfreuen
fragunfrag - Martin Kalesberger
-
googlest du: "include guard"
-
#ifndef = if not defined
Also wenn SALESITEM_H nicht definiert ist, geht es weiter. Wenn SALESITEM_H definiert ist, wird der Ablauf (in dem Fall das verarbeiten der Headerdatei) abgebrochen.
-
fragunfrag schrieb:
...
Ich verstehe leider nicht den Sinn und Zweck dieser Beispieles :(...Kann ich verstehen. Das versteht man auch besser, wenn man es mal weggelassen und sich mit den Fehlermeldungen rumgeschlagen hat
.Diese Technik begegnet dem Problem, dass in einer Compile-Einheit "alles" (soll nur eine Faustregel sein; jetzt nicht mit namespace-Erweiterungen kommen !) nur einmal deklariert/definiert werden darf. Besonders bei einer Klasse reagieren Compiler (notwendigerweise) ablehnend, wenn sie doppelt deklariert sind.
Eigentlich macht das ja auch keiner, dass er denselben Klassennamen für zwei Klassen verwendet ... jedenfalls nicht absichtlich - und da ist der springende Punkt.
Stell' Dir 3 Sourcen vor:// includefile1.h class A { // irgendwas ... };// includefile2.h #include "includefile1.h" // importiert die Deklaration von A class B { A a; // "hat" ein A };und
// mainFile.cpp #include "includefile1.h" // Deklaration von A #include "includefile2.h" // Deklaration von B int main(int argc, char* argv[]) { A a; // brauche ein A ... B B; // ... und ein B // .... damit mache ich was }Der Präprozesser macht beim Compile von mainFile.cpp aus den #includes eigentlich nichts anderes, als ein Reinkopieren des jeweiligen Fileinhalts:
deswegen bekommt der Compiler folgendes "gereicht":// "#include "includefile1.h" // Deklaration von A " wird zu: class A { // irgendwas ... }; // "#include "includefile2.h" // Deklaration von B" wird zu: // includefile2.h // "#include "includefile1.h" // importiert die Deklaration von A" wird zu // includefile1.h class A { // irgendwas ... }; class B { A a; // "hat" ein A }; int main(int argc, char* argv[]) { A a; // brauche ein A ... B B; // ... und ein B // .... damit mache ich was }(mag imer noch ein wenig unübersichtlich sein, lohnt sich aber, das einmal durchzuspielen. Denk' ran : JEDES "#include" wird ersetzt durch den jeweiligen Dateiinhalt.)
Und Voilà: 2 Deklarationen der Klasse A !
> Compiler bricht ab mit Fehlermeldung "Doppelte Klassendeklaration" o.ä.
In einem solch simplen Fall kann man diese Abhängigkeiten noch relativ einfach beherschen, wenn man das Inkludieren von includefile1.h in mainFile.cpp weglässt. Aber die Geschichte wird mit zunehmender Fileanzahl unübersichtlicher und unbeherrschbarer.
Einfacher ist es da, einen "Schalter" einzuführen, der dem Präprozesser sagt, ob dieses File schon inkludiert wurde oder nicht .... und dazu nimmt man konventionsgemäß eine Präproz-Variable, die genauso heißt wie das File selbst.
Dann kommt der Präproz das erste Mal an die Stelle
#ifndef INCLUDEFILE1_H_ // Nachschauen: "Aha, INCLUDEFILE1_H_ ist noch nicht definiert, also hier weitermachen #define INCLUDEFILE1_H_ // "Aha: Hier also definieren und weiter" class A { // Hier gibt's nix zu tun für den Präproz // irgendwas }; #endif // "OK, weiter"Beim zweiten Mal, dass er das File inkludiert wird's dann interessant:
#ifndef INCLUDEFILE1_H_ // Nachschauen: "Moooment: INCLUDEFILE1_H_ ist doch schon definiert, // also hier NICHT weitermachen, sondern das passenden #endif suchen // und alle Zeile bis dahin überspringen #endif // "OK, weiter"Schwupp, schon ist die 2. Deklaration weg.

Lange Rede, kurzer Sinn: dieses Konstrukt ist eine "Schalterabfrage", u8m Doppeltdeklarationen/-definitionen zu unterbinden.
Gruß,
Simon2.
-
Simon2 schrieb:
[...]
Compiler bricht ab mit Fehlermeldung "Doppelte Klassendeklaration" o.ä.
[...]Nop das stimmt nicht ganz: Du kannst Funktionen, Klassen (u.ä.) und auch externe Variablen so oft deklarieren wie du willst.
-
CodeFinder schrieb:
Simon2 schrieb:
[...]
Compiler bricht ab mit Fehlermeldung "Doppelte Klassendeklaration" o.ä.
[...]Nop das stimmt nicht ganz: Du kannst Funktionen, Klassen (u.ä.) und auch externe Variablen so oft deklarieren wie du willst.
Wenn man "o.ä." schreibt, stimmt's eigentlich immer
....OK, ich glaube zwar nicht, dass jemandem, der "include guards" nicht kennt, mit einer "Deklaration/Definition"-Debatte weitergeholfen wird (oder durch den "nackten" Hinweis, man könne so oft deklarieren, wie man will - weiß er wirklich, was jetzt an meiner Aussage falsch war und was ihn einer Lösung näherbringt ?), aber:
1 Zeile Code sagt mehr als 1000 Worte:
erlaubt:class A; // forward Deklaration class A { int f(); };NICHT erlaubt:
class A { int f(); }; class A { int f(); };-> "Compilermeldung: error: redefinition of `class A' ...previous definition of `class A'..."
Hier spricht er offensichtlich von "Definition" und nicht von Deklaration. Oben habe ich "Deklaration" gesagt, um mich von der "Definition der Memberfunktionen" abzugrenzen ... Wollte damit ausdrücken: "das Problem kann man nicht dadurch ausmerzen, dass man Fkt-Def. in ein cpp auslagert".Aber danke für die Klarstellung.

Gruß,
Simon2.
-
Wollte nur den Unterschied zwischen Deklaration und Definition darstellen.

:
class A; // (Forward) Deklaration class A; // (Forward) Deklaration class A; // (Forward) Deklaration class A; // (Forward) Deklaration class A; // (Forward) Deklaration class A; // (Forward) Deklaration class A; // (Forward) Deklaration class A { // Definition der Klasse A int f(); }; /* /!\ FEHLER /!\ class A { // Definition der Klasse A int f(); }; /!\ FEHLER /!\ */ int A::f() { return (1-1+0); // ^^ } /* /!\ FEHLER /!\ int A::f() { return (1-1+0); // ^^ } }; /!\ FEHLER /!\ */PS: Dein letzter Post war natürlich rischtisch.
