Hi,
ich möchte gerne abhängig davon, ob zwei Makros gleich sind,
unterschiedlichen Code generieren. Meine bisherigen Versuche sehen in
etwa so aus:
1
#define LED1_DDR DDRD
2
#define LED2_DDR DDRD
3
#if LED1_DDR == LED2_DDR
4
// Code
5
#endif
Leider wird das mit einer Fehlermeldung quittiert, die da lautet:
"error: operator '*' has no left operand".
Interessanterweise liegt das wohl daran, dass DDRD selbst ein Makro ist.
Ersetze ich nämlich DDRD durch z.B. jeweils "1", dann funktioniert es
tadellos.
Kennt ihr das Problem bzw. kennt ihr eine Möglichkeit es zu umgehen?
Vielen Dank!
Unlucky2012 schrieb:> #if LED1_DDR == LED2_DDR> // Code> #endif
Da spielt dir der Präprozessor einen Streich. Wann wird io.h
eingebunden? ist das mmcu-Makro für den Compileraufruf korrekt gesetzt?
Unsaubere Lösung:
Man könnte das in Hochsprachen-C mit einem leeren if-Block versuchen.
Das if würde ausgewertet und der Compiler und nicht der Präprozessor
erkennt, dass sie gleich sind. Das geht aber nur gut, wenn es dir um
Ausgabe einer Warnung geht.
mfg mf
Damit ist zwar theoretisch erstmal jede Codevariante im Programm
enthalten, obwohl natürlich nur einer der Zweige jemals ausgeführt wird.
Weil das if aber auf einem konstanten Ausdruck besteht, ist jeder
halbwegs aktuelle Compiler in der Lage, die überflüssige Hälfte
wegzuoptimieren.
Mini Float schrieb:> Da spielt dir der Präprozessor einen Streich. Wann wird io.h> eingebunden? ist das mmcu-Makro für den Compileraufruf korrekt gesetzt?
io.h wird als erste Datei überhaupt eingebunden. mmcu Makro wird von
meiner Umgebung (Eclipse mit AVR-Plugin) korrekt gesetzt.
Klaus Wachtler schrieb:> Weil das if aber auf einem konstanten Ausdruck besteht, ist jeder> halbwegs aktuelle Compiler in der Lage, die überflüssige Hälfte> wegzuoptimieren.
Ja, nur würde ich das schon ganz gerne über den Präprozessor lösen. Dann
sieht es auch ein menschlicher Leser. Außerdem ist es dann nicht von der
Optimierungsstufe abhängig.
Gibt es denn ansonsten keine "vernünftige" Lösung?
Unlucky2012 schrieb:> Gibt es denn ansonsten keine "vernünftige" Lösung?
Ich mache es so:
1
#define CONCAT2x(a, b) a##b
2
#define CONCAT2(a, b) CONCAT2x(a, b)
3
4
// Config
5
6
#define PORT1 A
7
#define PORT2 A
8
9
// HW access
10
11
#define DDR_PORT1 CONCAT2(DDR, PORT1)
12
#define DDR_PORT2 CONCAT2(DDR, PORT2)
13
14
#if PORT1 == PORT2
15
...
16
#else
17
...
18
#endif
D. h. beim Vergleich kommt nichts "externes" ins Spiel, was den
Vergleich stört. Es ist auch eine Trennung zwischen "Konfiguration" und
"HW-Zugriff", was eine eventuelle Portierung auf eine andere Architektur
erleichtert.
Hast du das mal ausprobiert? Es hat nämlich einen Haken: Es funktioniert
nicht. Wenn weder A noch B definiert sind, dann ist
#if A == B
nämlich ein gültiger Präprozessor-Ausdruck, und mit dem exakt gleichen
Ergebnis wie
#if A == A
Der Ausdruck in einem #if Statement wird numerisch ausgewertet, nicht
als String. Ein nicht definiertes Symbol ist dabei, anders als in C
selbst, kein Fehler, sondern steht für 0. Somit ist
#if A == B
eigentlich
#if 0 == 0
Und zur ursprünglichen Frage: Mit dem Präpozessor ist das nur möglich,
wenn die Makros einfache numerische Ausdrücke sind. Was auf Ports wie
DDRA nicht zutrifft. Folglich ist das mit dem Präprozessor in dieser
Form nicht möglich.
Rolands Variante funktioniert, wenn man sich die Mühe macht, die Ports
vergleichbar zu 8051 umzubenennen, also 1,2,3 statt A,B,C. Also alle
Register von PORT A konsequent mit #defines versieht, die daraus PORT1,
PIN1 und DDR1 machen:
1
#define P1 1
2
#define P2 2
3
4
#if P1 == P2
5
#error 1
6
#else
7
#error 2
8
#endif
9
10
#define CONCAT2x(a, b) a##b
11
#define CONCAT2(a, b) CONCAT2x(a, b)
12
13
#define DDR1 DDRA
14
#define DDR2 DDRB
15
16
#define DDR_PORT1 CONCAT2(DDR, P1)
17
#define DDR_PORT2 CONCAT2(DDR, P2)
Aber ob man dann selber nach einiger Zeit noch durchblickt?
A. K. schrieb:> Hast du das mal ausprobiert? Es hat nämlich einen Haken: Es funktioniert> nicht
Erwischt. Das kommt vom Zusammenschustern, und die Grundlage verglich
numerische Werte (da ging es um Doppelbelegung eines Timers).
> Rolands Variante funktioniert, wenn man sich die Mühe macht, die Ports> vergleichbar zu 8051 umzubenennen, also 1,2,3 statt A,B,C.
Ich hab's mir bei den LPCs abgeschaut ;-)
In der Tat verwende ich für AVR/STM32/PIC32 GPIO eine ähnliche Variante,
nämlich zusätzlich zu A, B, C noch 0, 1, 2 in der Konfiguration zu
verwenden. Das erste findet Verwendung in Makros, die numerische
Variante für "parametrisiertes" GPIO.
LPC/RX/MSP430 verwenden numerische Port-IDs, dort ist Port-Name =
Port-ID.
A. K. schrieb:> Aber ob man dann selber nach einiger Zeit noch durchblickt?
Das geht schon. Es nervt etwas, jeden GPIO-Pin mit drei Zeilen zu
beschreiben:
1
#define DEFAULT_LED_RED_0_PORT_NAME B
2
#define DEFAULT_LED_RED_0_PORT_ID 1
3
#define DEFAULT_LED_RED_0_PIN 5
Ich weiß nicht, ob man von der Zahl 1 auf den String B mittels
Präprozessor schließen kann, dann könnte ich mir die erste Zeile sparen.
bzw.
1
#define DEFAULT_LED_RED_0_PORT_NAME 2
2
#define DEFAULT_LED_RED_0_PORT_ID 2
3
#define DEFAULT_LED_RED_0_PIN 4
So passt das für alle Plattformen, den Rest erledigen Makros (zugegeben
teilweise mit wilden CONCATs) oder Funktionen. Die Komplexität liegt
aber weder in der Konfiguration noch im Aufruf.