Prüfen ob zwei Makros (Ports) gleich sind

Gast #2700476
Lesenswert?

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!
#2700486
Lesenswert?

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
#2700499
Lesenswert?

Es geht schon:
1
    if( &LED1_DDR == &LED2_DDR )
2
    {
3
       ...
4
    }
5
    else
6
    {
7
       ...
8
    }

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.
Gast #2700767
Lesenswert?

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?
#2701167
Lesenswert?

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.
#2701184
Lesenswert?

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
#2701224
Lesenswert?

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?
#2701306
Lesenswert?

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.

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