Forum: Mikrocontroller und Digitale Elektronik Präprozessor findet #define nicht


von tim (Gast)


Lesenswert?

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"

von Sam P. (Gast)


Lesenswert?

Klar, denn während die cpp-Datei übersetzt wird, ist ID nicht definiert. 
Die ist nur definiert während main.cpp übersetzt wird.

von Sam P. (Gast)


Lesenswert?

Oder anders gesagt: #define funktioniert nicht so wie du denkst / dir 
erhoffst. Du könntest ID über Compileroptionen definieren, dann klappt 
das.

von Hmm (Gast)


Lesenswert?

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.

von Hmm (Gast)


Lesenswert?

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.

von tim (Gast)


Lesenswert?

@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.

von tim (Gast)


Lesenswert?

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 ;-)

von Hmm (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hmm (Gast)


Lesenswert?

>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. :-)

von kopfkratzer (Gast)


Lesenswert?

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
1
class CGlobalConsts
2
{
3
 private:
4
 const unsigned uID = 100;
5
 const float    fVersion = 1.02;
6
7
 public:
8
 unsigned getID()
9
 {
10
  return uID;
11
 }
12
13
 float getVersion()
14
 {
15
  return fVersion;
16
 }
17
}
18
19
class CMyProg : CGlobalConsts
20
{
21
 ...
22
}

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.