Guten Morgen zusammen,
ich habe ein Problem, das eher in die Richtung Kuriosum einzuordnen ist:
Ich muß im Präprozessor zwei Variablen a und b definieren, bei denen ich
sicher sein muß, daß sie aus der gleichen Menge sind.
1
// Header-Datei mit Einstellungen
2
#define a
3
#define b
4
5
[...]
6
7
// Tiefer im Code (keine Benutzereinstellungen)
8
#define M1 {0,1,2,3,4} // Mengenklammern
9
#define M2 {5,6,7,8} // Jedes Element kommt nur einmal vor
10
#define M3 {10,11}
11
12
// Wenn a und b in verschiedenen Mengen sind, Fehler ausgeben
13
// Wenn a oder b in keiner Menge ist auch Fehler ausgeben
14
#error a und b sind ungueltige Parameter
Das ist natürlich total einfach zur Laufzeit zu bewerkstelligen - aber
geht soetwas auch im Präprozessor?
Viele Grüße
W.T.
P.S.: Was ist eigentlich peinlicher: Viele Rechtschreibfehler oder viele
Edits beim Postingstart?
Walter Tarpan schrieb:> Ich muß
Sagt wer? Und wenn ja, warum?
Manche Probleme lassen sich halt nur durch vollständiges Ignorieren
lösen.
Der C-Preprozessor ist für so etwas nicht gedacht, kann es nicht, und
soll es auch nicht können.
Wenn du das unbedingt zur Compilezeit erkennen musst, wirst du einen
selbstgebauten Pre-Preprozessor einsetzen müssen. Also schreib dir ein
Script in der Scriptsprache deiner Wahl (oder auch in C), das dein
Sourcefile parst, erkennt, was es erkennen soll, und bau das mit in
deine toolschain ein.
Oliver
Oliver schrieb:> Sagt wer? Und wenn ja, warum?Walter Tarpan schrieb:> Ich muß im Präprozessor zwei Variablen a und b definieren
Dieser Teil ist Pflicht.
Walter Tarpan schrieb:> bei denen ich> sicher sein muß daß sie aus der gleichen Menge sind.
Dieser Teil ist auch Pflicht - aber problemlos der Verantwortung des
Bearbeiters der Header-Datei anzulasten.
Das den Präprozessor überprüfen zu lassen ist Kür. Deswegen auch die
Einleitung:
Walter Tarpan schrieb:> ich habe ein Problem, das eher in die Richtung Kuriosum einzuordnen istA. K. schrieb:> Kommt drauf an in welchem. Im M4 hast du bessere Chancen als im CPP
Puh, ich wußte gar nicht, daß es für die GCC-Toolkette mehrere
Präprozessoren zur Auswahl gibt. Ich nutze den AVR-GCC von AtmelStudio
6.1 (welche Version das ist, kann ich momentan nicht nachgucken). Aber
das ist nebensächlich - das Thema ist deutlich interessanter als
nützlich.
Walter Tarpan schrieb:> Puh, ich wußte gar nicht, daß es für die GCC-Toolkette mehrere> Präprozessoren zur Auswahl gibt.
Der M4 hat mit GCC nichts zu tun, lässt sich aber per Makefile
vorschalten. Entstanden ist er im Zusammenhang mit Fortran.
Es ist ein oft gemachter Irrtum, daß bei einem #define irgendwas
berechnet oder geprüft wird.
Der Präprozessor ist ein reiner Textersetzer und prüft nichts.
Er kann nur im #if Integer-Konstanten vergleichen, sonst nichts.
Erst der Compiler nimmt sich den ersetzten Text zu Gemüte und versucht
seine Syntaxregeln darauf anzuwenden.
Peter Dannegger schrieb:> Er kann nur im #if Integer-Konstanten vergleichen, sonst nichts
Naja, mehr soll er im Grunde genommen ja auch nicht. Integer-Konstanten
vergleichen und bei Unzufriedenheit einen Compile-Fehler werfen.
Die defines mit den drei Mengen M1, M2, M3 waren nur zur
Veranschaulichung, was ich mit "Mengen" überhaupt meine.
Walter Tarpan schrieb:> Naja, mehr soll er im Grunde genommen ja auch nicht. Integer-Konstanten> vergleichen und bei Unzufriedenheit einen Compile-Fehler werfen.
Dann mußt Du ja einfach nur die Vergleiche hinschreiben.
Mir ist allerdings nicht klar, wie Du Dein Mengen-Dingens durch
Vergleiche rauskriegen willst.
Vergleiche können nur x == y, x > y und x < y ermitteln.
Zusätzlich kann der Präprozessor noch #ifdef, d.h. wurde ein Symbol
vorher definiert.
Peter Dannegger schrieb:> Es ist ein oft gemachter Irrtum, daß bei einem #define irgendwas> berechnet oder geprüft wird.
Die Ausdrücke in #if conditionals werden aber vom Präprozessor
evaluiert.
Man kann daher sowas machen:
A. K. schrieb im Beitrag #3432531:
> Das war nur seine Art, es zu "veranschaulichen" - d.h. alle gezielt zu> verwirren.
OK, die Schreibweise in Code-Blöcke zu packen hat vielleicht etwas
Verwirrung gestiftet. Gemeint war: Es existieren drei (konstante) Mengen
M1, M2, M3 mit:
M1 = {0,1,2,3,4}
M2 = {5,6,7,8}
M3 = {10,11}
und zwei Konstanten a und b. Wie ich die Mengen M1-M3 als Liste
beschreibe ist auch egal. Es ist auch nicht zwangsläufig so, daß die
Mengen direkt aufeinanderfolgende Zahlen enthalten. Erlaubt sind alle a
und b, bei denen beide in der gleichen Menge sind, also:
a = 1,b = 0 -> erlaubt (beide in M1)
a = 1,b = 5 -> nicht erlaubt (beide in unterschiedlichen Mengen)
a = 1,b = 12 -> nicht erlaubt (nicht beide in der gleichen Menge)
Für jedes erlaubte a kann ich also prüfen, ob b erlaubt ist- was eine
lange Vergleichsliste ist - zumal die "echte" Liste 5 Mengen und 128
Werte hat.
In C läßt sich das komfortabel mit Schleifen testen.
Und im Präprozessor sorgt es wohl für Verwirrung :-)
Luther Blissett schrieb:> Peter Dannegger schrieb:>> Es ist ein oft gemachter Irrtum, daß bei einem #define irgendwas>> berechnet oder geprüft wird.>> Die Ausdrücke in #if conditionals werden aber vom Präprozessor> evaluiert.>> Man kann daher sowas machen:> /* foo.c */> #define ELEM(X) (1<<(X))>> #define M1 (ELEM(0)|ELEM(1)|ELEM(2)|ELEM(3)|ELEM(4))> #define M2 (ELEM(5)|ELEM(6)|ELEM(7)|ELEM(8))> #define M3 (ELEM(10)|ELEM(11))>> #define BOTH (ELEM(A)|ELEM(B))>> #if ((BOTH & M1) != BOTH) && ((BOTH & M2) != BOTH) && ((BOTH & M3) !=> BOTH)> #error "A und B müssen in der gleichen Menge sein"> #endif>> und dann:> $ gcc -DA=5 -DB=6 -c foo.c> $ gcc -DA=1 -DB=6 -c foo.c> foo.c:13:3: error: #error "A und B müssen in der gleichen Menge sein"
Das muß ich mir mal in Ruhe anschauen und auf einem Blatt Papier
auseinandernehmen.
Walter Tarpan schrieb:> Das muß ich mir mal in Ruhe anschauen und auf einem Blatt Papier> auseinandernehmen.
Das funktioniert leider nur mit Werten kleiner 64.
Wenn deine Mengen wirklich konstant sind, und sich auch nie ändern, geht
es natürlich "zu Fuß":
1
#define A 64
2
#define B 59
3
4
//Mengen als Einzelelemente definieren
5
6
//Menge 1
7
#define M11 0
8
#define M12 1
9
#define M13 4
10
#define M14 7
11
12
//Menge 2
13
#define M21 62
14
#define M22 64
15
#define M23 77
16
17
//Merker
18
#define MENGEA -1
19
#define MENGEB -1
20
21
// und jetzt A für Element einzeln vergleichen, und Merker setzen, wenn in Menge
22
#if (A == M11) || (A == M12) || (A == M13)|| (A == M14)
Oliver schrieb:> Das funktioniert leider nur mit Werten kleiner 64.
Bei größeren Werten muss man die Mengen wohl auftrennen, also z.B.
M1_LOW and M1_HIGH. Dann lautet die Bedingung für "A und B sind in M1"
jetzt "A in M1_LOW oder A-32 in M1_HIGH und B in M1_LOW oder B-32 in
M1_HIGH"
Die Fragestellung ist mathematisch schon zweifelhaft.
a und b sind immer in der gleichen Menge M , etwa für M = { a, b }.
Ansonsten ist die Fragestellung nur dann sinnvoll, wenn die Mengen, um
die es geht, disjunkt sind, d.h. eine Klasseneinteilung bzw.
Äquivalenzrelation definieren.
Vielleicht ist es einfacher, sich ein kleines DOS-Programm zu schreiben,
was die Datei einliest und nach Deinen Regeln überprüft.
Oder man fügt die Überprüfung über einen Compile-Switch mit ein und läßt
es im Simulator laufen.
Peter Dannegger schrieb:> Vielleicht ist es einfacher, sich ein kleines DOS-Programm zu schreiben,> was die Datei einliest und nach Deinen Regeln überprüft.
Wie schon oben geschrieben: Es ist eine Frage rein aus Neugier. Wer in
Headerdateien herumfummelt trägt auch die Verantwortung, das konsistent
zu tun.
Die Plausibilitätsprüfung von Konstanten im Präprozessor ist einfach ein
Thema, das mich interessiert.