C++ Compiler Einstellung zu defines

Gast #5664667
Lesenswert?

Hallo.

Const möchte ich aus bestimmten Gründen mal nicht verwenden. Ich habe 
aktuell viele mit #define definierte Werte, die sich gegeneinander auf 
Plausibelität prüfen. Bei einem Schreib- oder sonstigem Fehler greift 
der Compiler ins leere und gibt eine vorgesehene Meldung nicht aus, 
die eigentlich kommen müsste (z.B. Wert zu groß).

Gibt es eine Möglichkeit, dem Compiler zu sagen, dass er mit Fehler 
abbrechen soll, wenn er über eine Definition stolpert, die nicht 
definiert ist?

Beispiel
1
#define TEST 123
2
#if (TETS > 100)              // falsche Schreibweise
3
#error "Der Wert ist zu groß" // Diese Meldung bleibt natürlich aus
4
#endif                        // erzeugt aber auch keinen Fehler
5

6
void setup() {
7
}
8

9
void loop() {
10
}

Es betrifft natürlich nur "wegoptimierte" Definitionen, auf die nicht 
zugegriffen wird (zuküftige Ressourcen, die aber jetzt schon festgelegt 
worden sind). Ich verwende GCC.
Persönliche Seite #5664686
Lesenswert?

define schrieb:
> Gibt es eine Möglichkeit, dem Compiler zu sagen, dass er mit Fehler
> abbrechen soll, wenn er über eine Definition stolpert, die nicht
> definiert ist?

Nein. Abgesehen von der Spitzfindigkeit, daß der Compiler #defines 
sowieso nicht zu Gesicht bekommt (das macht der Präprozessor), würdest 
Du damit annähernd jeden existierenden Code unbrauchbar machen, denn das 
"Feature" undefinierter #defines wird intensiv genutzt -- dafür bietet 
der Präprozessor eigens #ifdef bzw. #if defined.
Gast #5664765
Lesenswert?

define schrieb:
> Gibt es eine Möglichkeit, dem Compiler zu sagen, dass er mit Fehler
> abbrechen soll, wenn er über eine Definition stolpert, die nicht
> definiert ist?

Ja, das geht (aber wie bereits geschrieben, macht das der Präprozessor).

Typische Pattern:
1
#if 1/defined(TEST)
2
// do something if TEST is defined
3
#endif
1
#if 1/defined(TEST) && (TEST != 0)
2
// do something if TEST evaluates to TRUE
3
#else
4
// do something if TEST evaluates to FALSE
5
#endif
Gast #5664867
Lesenswert?

Ok, Hauptsache mal zu Wort gemeldet.

Die Sache ist, dass der Präprozessor nicht definierte Symbole zu 0 
auswertet aber keinen Fehler erzeugt. Das ist historisch so. Das 
bedeutet bei
1
#if TEST != 0
2
// tue A
3
#else
4
// tue B
5
#endif

kann sich der Entwickler nicht sicher sein, ob B eincompiliert wird, 
weil TEST definiert und auf 0 gesetzt wurde, oder weil TEST gar nicht 
definiert ist. Das macht bei großen Projekten Probleme, wenn irgendwo 
ein #include vergessen wurde. Dann kann es passieren, dass verschiedene 
Modulen mit inkonsistenter Konfiguration compiliert werden. Will man 
nicht.

Wenn man statt dessen also einen Fehler möchte, kann man das so machen:
1
#if 1/defined(TEST) && (TEST != 0)
2
// tue A
3
#else
4
// tue B
5
#endif

Der Fehler entsteht, falls TEST nicht definiert ist, da der Präprozessor 
bei der Division durch 0 abbricht (1/0). Ist TEST definiert, steht dort 
(1/1) und somit
1
#if 1 && (TEST != 0)

Für das erfolgreiche compilieren muss TEST dann definiert sein und A 
wird eincompiliert falls TEST != 0 und andernfalls wird B eincompiliert 
falls TEST == 0. So wie man es erwarten würde - nur mit Fehler beim 
compilieren, falls TEST nicht definiert ist.
Gast #5664937
Lesenswert?

x^2 schrieb:
> Der Fehler entsteht, falls TEST nicht definiert ist, da der Präprozessor
> bei der Division durch 0 abbricht (1/0). Ist TEST definiert, steht dort
> (1/1) und somit

Ja genau. Wie gesagt:
ifndef und !defined() kennste?
Was soll der Vorteil von der Division durch Null sein?
Gast #5664961
Lesenswert?

Ich finde es ist v.a. bei Verschachtelung übersichtlicher. Es läßt sich 
auch leicht automatisch prüfen (eine kleine regex reicht) ob es irgendwo 
fehlt. Im Vergleich:
1
#ifdef TEST
2
#if TEST != 0
3
// tue A
4
#else
5
// tue B
6
#endif
7
#else
8
#error "Missing TEST"
9
#endif
1
#if 1/defined(TEST) && (TEST != 0)
2
// tue A
3
#else
4
// tue B
5
#endif

Nachteil ist sicher, dass man sich erst mal daran gewöhnen muss, um 
nicht jedesmal bei der Zeile stutzig hängen zu bleiben.
Gast #5664964
Lesenswert?

x^2 schrieb:
> #ifdef TEST
> #if TEST != 0
> // tue A
> #else
> // tue B
> #endif
> #else
> #error "Missing TEST"
> #endif

#ifndef TEST
#error "Missing TEST"
#elif TEST
// tue A
#else
// tue B
#endif

Vorteil: Man hat eine vernünftige Fehlermeldung, in der man auch noch 
erklären kann, was zu tun ist um das zu beheben, statt einer Division 
durch Null.
Gast #5664965
Lesenswert?

OK, aus den Infos kann ich was machen. danke.

Die Makrobefehle kenne ich alle. Es sind ja nicht viele.

#ifdef ist keine Lösung. Will man jede Deklaration mit ifdef 
hinterprüfen, kommt man zu nichts anderem. Ab einer bestimmten 
Programmgröße jedenfalls. Zumal sich da auch wieder Fehler einschleichen 
können.

Die Plausichecks (natürlich vom Parser und nicht vom Compiler) sollen 
Konfigurationsfehler verhindern, und tun das auch sehr effizient. Mir 
ist es gestern aber passiert, dass ich eine Passage gelöscht habe, 
wodurch bestimmte Deklarationen nicht mehr gebraucht wurden. Diese 
blieben aber stehen, ich bin ja auch nur ein Mensch, und irgendwann habe 
ich mich gefragt, wieso da keine Meldung kommt, wenn auf verwaiste 
Ressourcen zugegriffen wird. Aber jetzt kenne ich ja den Grund. In 
Includfiles stehen jede Menge ungenutzte defines, das darf natürlich 
keinen Fehler geben. Wenn an auf diese defines zugreift, auf 
Präprozessor- oder Parserebene, sollte aber doch wenigstens eine Meldung 
kommen, statt den Wert 0 zugrunde zu legen. Das war mein Anliegen. Wenn 
das nicht geht, komme ich damit auch zurecht, ist halt anstrengend bei 
hunderten Zeilen Plausichecks. also danke nochmal.
Angehängte Dateien:
Gast #5664972
Lesenswert?

1
$ cat t.c 
2
#if FOO
3
#endif
4
int main(void){}
5

6

7

8
$ gcc -Wundef -Werror=undef -o t t.c
9
t.c:1:5: error: "FOO" is not defined, evaluates to 0 [-Werror=undef]
10
 #if FOO
11
     ^~~
12
cc1: some warnings being treated as errors

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren