Hallo.
Hab ein Problem mit dem Präprozessor.
Ein Wert soll in der Hauptquelldatei per #define definiert werden und
dann in einem header verwendet werden. wenn nur der header, der mit
diesem Wert weiterarbeitet im Projekt drin ist, klappt auch alles.
Nur wenn jetzt die dazugehörige .cpp-Datei miteingebunden wird, gibts ne
Fehlermeldung vom Präprozessor, der mir sagt, dass der Wert nicht
definiert wurde.
Ich bin gerade ein wenig ratlos, warum der Wert denn nicht im sourcefile
des headers gefunden werden kann.
Einmal die Auszüge: (Ist allerdings C++)
1
//"header.h"
2
3
#pragma once
4
5
#ifndef ID
6
#error ID ist nicht definiert!
7
#endif
1
//.cpp von "header.h"
2
3
#include"header.h"
1
//"main.cpp"
2
3
#define ID 17
4
5
#include"header.h"
Als Fehlermeldung kommt:
"#error ID ist nicht definiert!" in "header.h"
und
"'ID' was not declared in this scope"
Sam P. schrieb:
>#define funktioniert nicht so wie du denkst / dir erhoffst.
Welche Antwort die einigermaßen naheliegende Frage aufwirft, wie define
funktioniert. Stimmst Du mir zu?
In der Regel wird ein Programm aus mehreren C/CPP-Dateien (was es ist,
spielt hier keine Rolle) in genauso vielen Aufrufen des Compilers
definiert.
Das ergibt je C-Datei eine Objektdatei.
Der Compiler sammelt nicht etwa Informationen über Variablen, Typen
und auch Defines über alle C-Dateien. Falls das so wäre, müsste es
eine Methode geben, dem Compiler mitzuteilen, das jetzt ein neues
Projekt übersetzt wird. Gibt es aber nicht.
Die Absicht dabei ist, vollständig eigenständige Objektdateien zu
erhalten, die bei Bedarf mit beliebigen anderen Objektdateien gelinkt
werden können ohne das der Quellcode nochmal angefasst werden muss.
Daraus folgt, das der Compiler bei der Übersetzung von main.cpp zwar das
Define sieht und das auch bei der Bearbeitung der dort eingefügten Datei
header.h berücksichtig. Aber bei der zweiten, getrennt davon erfolgenden
Kompilierung von ".cpp" (Was immer eine Datei ohne Namen hier zu
bedeuten hat) weiss er nichts mehr davon und meldet was Du vorgesehen
hast.
Wissenswert ist aber auch noch, das genau genommen, nicht der Compiler
die Defines behandelt, sondern der Preprozessor. Sinngemäß gilt hier
aber das selbe.
Uuups:
In der Regel wird ein Programm aus mehreren C/CPP-Dateien (was es ist,
spielt hier keine Rolle) in genauso vielen Aufrufen des Compilers
compiliert .
Das ergibt je C-Datei eine Objektdatei.
@Hmm: Ja, hört sich logisch an. Bin eher aus der C++ Ecke und kenne mich
mit Pr(a)eprozesssordirektiven nciht so aus, da ich sie bis jetzt wenig
benutzen musste. Und Lösung würde darin bestehen, wenn ich entweder in
den Compileroptionen definiere, dass ich noch ein define in der
"namentlich nicht genannten Quelldatei" haben möchte?
Oder ich müsste das nicht über den Pr(a)eprozessor lösen sondern dem
Konstruktor übergeben.
Ist es möglich, beim ersten Aufruf von "header-h" -wrs durch main.cpp-
'ID' in der Klasse abzuspeichern und für den nächsten Aufruf das
'#ifndef' auszuklammern? wäre so ein Zwischenweg möglcih, oder
scheiterts dran, dass der Präprozessorlauf vor der Compilierung
durchgeführt wird?
@Sam: ne genauere Beschreibung oder ein Link wäre hilfreich.
Danke schonmal für die Hilfe ;-)
Grundsätzlich gibt es in der Beziehung zu Präprozessor-Direktiven und
deren Behandlung keinen Unterschied zwischen C und C++.
Es wäre ganz gut zu wissen, was Du eigentlich bezwecken wilst.
Das "normale" wäre, das Define in einer .h resp. .hpp Datei zu schreiben
und diese H-Datei eben überall zu includen wo es gebraucht wird.
Ich bin gewohnheitsmäßig eher kein Benutzer von defines in den
Compiler-Optionen obwohl ich das schon benutzt habe.
Wie gesagt: Schreib mal um was es eigentlich geht.
Was ist das eigentlich mit der "namenlosen" .cpp Datei? Habe ich noch
nie gesehen, sowas.
tim schrieb:> Ist es möglich, beim ersten Aufruf von "header-h" -wrs durch main.cpp-> 'ID' in der Klasse abzuspeichern und für den nächsten Aufruf das> '#ifndef' auszuklammern? wäre so ein Zwischenweg möglcih, oder> scheiterts dran, dass der Präprozessorlauf vor der Compilierung> durchgeführt wird?
Welchen Teil von
a.cpp und main.cpp werden unabhängig voneinander compiliert.
Wenn der Compiler a.cpp compiliert, weiß er nichts von main.cpp und
umgekehrt wenn er main.cpp compiliert, weiß er nichts von a.cpp
verstehst du nicht?
Sieh dir die Datei a.cpp an.
Löse alle #include auf (kopier dir den Text aus der angegebenen Datei an
die Stelle des include). Der Text, der da rauskommt, der wird
compiliert. Was in anderen *.cpp Dateien steht, interessiert nicht.
In C oder in C++ gibt es keinen Projektgedanken, in dem sich der
Compiler aus mehreren Dateien die Dinge zusammensucht und selbsttätig
Querverweise herstellt.
Du wirfst ihm einen Text vor, und der wird compiliert. Aus, Ende, Punkt.
Mehr passiert nicht.
Dann wirfst du ihm einen anderen Text vor, der wird auch compiliert.
Ohne Ansehen dessen was vorher passiert ist oder nachher passieren wird.
Dei einzeln compilierten Teile werden dann vom Linker zu einem
Komplettprogramm zusammengesetzt.
tim schrieb:> Ist es möglich, beim ersten Aufruf von "header-h" -wrs durch main.cpp-> 'ID' in der Klasse abzuspeichern und für den nächsten Aufruf das> '#ifndef' auszuklammern?
Nein.
> wäre so ein Zwischenweg möglcih,
Nein.
> oder> scheiterts dran, dass der Präprozessorlauf vor der Compilierung> durchgeführt wird?
Genau so ist es. Deswegen heißt er ja auch Präprozessor und nicht
Präcompiler. Der Präprozessor weiß nichts über die Semantik von C/C++,
sondern führt einfach "dumme" Textersetzungen durch und kann auch keine
Informationen zu anderen Compilerläufen hinüberretten.
Dass du in deiner Entwicklungsumgebung ein Projekt machst, in dem du
alle zum Projekt gehörenden CPP Files und Header Files einbindest, ist
eine Sache deiner Entwicklungsumgebung.
Die darfst du aber nicht mit dem Compiler verwechseln. Eine IDE ist
einfach nur ein Programm, welches ein Projekt aufbaut und dir einen
Editor zur Verfügung steht. Es ist ein Frontend. Wenn es etwas zu
compilieren gilt, dann startet diese IDE den eigentlichen Compiler und
lässt ihn File für File compilieren. Und dann gelten die Regeln des
Compilers bzw. Linkers. Und die lauten: Es gibt kein Projekt - es gibt
nur dieses eine CPP File, welches jetzt gerade compiliert wird.
>Es gibt kein Projekt - es gibt nur dieses eine CPP File, welches jetzt >gerade
compiliert wird.
Und damit kann man in der Regel gut leben. Mir gelingt es jedenfalls
seit ca. 30 Jahren. Denk nich so kompliziert. Das gibt nur
Kopfschmerzen! Auch im übertragenen Sinne.
Einfach das Define in eine Header-Datei. Und die includen wo es nötig
ist.
Dann geht alles wie von selbst. :-)
kopfkratz
Also die einfachste Lösung wäre das Du die ID in eine extra .h Datei
auslagerst und dann überall importierst.
Z.B.:
1
//id.h
2
#ifndef IDHEADER
3
#define IDHEADER
4
5
#define ID 100
6
7
#endif
1
//"header.h"
2
3
#include"id.h"
4
5
#pragma once
6
7
#ifndef ID
8
#error ID ist nicht definiert!
9
#endif
1
//"main.cpp"
2
3
#include"id.h"
4
#include"header.h"
Es macht sowieso mehr Sinn globale Werte entweder in der Basisklasse
direkt als const anzulegen oder wie beschrieben in einer globalen Header
Datei die überall eingebunden wird.
Die Variante mit der Klasse ist bessere OO :-P
Karl Heinz Buchegger schrieb:> In C oder in C++ gibt es keinen Projektgedanken, in dem sich der> Compiler aus mehreren Dateien die Dinge zusammensucht und selbsttätig> Querverweise herstellt.
Und um es noch weiter zu präzisieren: selbst dann, wenn man einem
Compileraufruf mehrere C-Quellen übergibt, werden diese hinsichtlich der
Syntax und Semantik vollständig separat betrachtet.
Lediglich einige Optimierungen können dann gemeinsam durchgeführt
werden, z.B. modulübergreifende Inline-Funktionen oder optimierte
Sprungtabellen. Dies ist aber im Sprachumfang nicht sichtbar.