Präprozessor-Makro verschachteln

OP #4536255
Lesenswert?
• ▲
▼
Hallo - beisse mir immer noch die Zähne an folgendem Proible aus.

Ich würde gerne aus;
  #define AUSGANG_SET_HIGH(port,mask) ((port) |= (1<<mask))
  #define BATT_ON (AUSGANG_SET_HIGH(PORTA,PA4))
(Funktioniert einwandfrei!)

solch eine Parametrierung machen;
  #define AUSGANG_SET_HIGH(port,mask) ((port) |= (1<<mask))
  #define PORT_BATT_OUT(PORTA,PA4)
  #define BATT_ON (AUSGANG_SET_HIGH(PORT_BATT_OUT))
Compiler meckert!

Obwohl nach meine Verständnis folgender Ersatz raus kommen sollte;
  #define BATT_ON (AUSGANG_SET_HIGH((PORTA,PA4)))

Auch ohne Leerzeichen zw. BATT_ON(AUSG...) klappts nicht.
Syntaxfehler?
Gast #4536273
Lesenswert?
• ▲
▼
Hallo

und obwohl bei deinem Verständnis was anders rauskommt als bei deiner 1. 
Lösung ist der Compiler schuldig ???

__Son´s B. schrieb:
> Obwohl nach meine Verständnis folgender Ersatz raus kommen sollte;
#define BATT_ON (AUSGANG_SET_HIGH((PORTA,PA4)))

__Son´s B. schrieb:
> #define BATT_ON (AUSGANG_SET_HIGH(PORTA,PA4))

zähl doch einfach mal die Anzahl der Klammern nach ...

mfg

DerDan
#4536334
Lesenswert?
• ▲
▼
Tom schrieb:
> Was man nicht alles tun muss, um die bösen performance-mordenden
> Funktionen zu vermeiden...

Niemand muß sowas, es gibt bessere Möglichkeiten, z.B.:
1. Portpins als Bitvariablen definieren
2. Inline-Funktionen

__Son´s B. schrieb:
> Compiler meckert!

Gehts bitte noch ungenauer?
Copy&Paste den genauen Fehlertext!
Hänge den Quelltext als Anhang an, dann kann man sogar die Zeilennummer 
in der Meldung zuordnen.
Moderator Persönliche Seite #4536432
Lesenswert?
• ▲
▼
__Son´s B. schrieb:
> Warum?

Du solltest dir hin und wieder mal ansehen, was aus dem Präprozessor
so hinten „herausfällt“.  (avr-gcc ... -E)  Dann würde dir vielleicht
auffallen, dass der Präprozessor von C keine Ahnung hat sondern stur
Texte ersetzt, und vielleicht entdeckst du dann auch mal das unsinnige
Semikolon im Zeichenstrom. ;)

Ansonsten funktioniert das, was du machen willst, zweistufig.

Ich hatte meine Lösung schon mal gepostet, auch wenn sie „W.S.“ nicht
gefiel. ;-)
1
#define GLUE(a, b)     a##b
2

3
/* single-bit macros, used for control bits */
4
#define SET_(what, p, m) GLUE(what, p) |= (1 << (m))
5
#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
6
#define GET_(/* PIN, */ p, m) GLUE(PIN, p) & (1 << (m))
7
#define SET(what, x) SET_(what, x)
8
#define CLR(what, x) CLR_(what, x)
9
#define GET(/* PIN, */ x) GET_(x)
10

11
#define ASSIGN_(what, p, m, v) GLUE(what, p) = (GLUE(what, p) & \
12
                                                ~((1 << (m)) | (1 << ((m) + 1)) | \
13
                                                  (1 << ((m) + 2)) | (1 << ((m) + 3)))) | \
14
                                                ((v) << (m))
15
#define READ_(what, p, m) (GLUE(what, p) & ((1 << (m)) | (1 << ((m) + 1)) | \
16
                                            (1 << ((m) + 2)) | (1 << ((m) + 3)))) >> (m)
17
#define ASSIGN(what, x, v) ASSIGN_(what, x, v)
18
#define READ(what, x) READ_(what, x)
19

20
...
21
  SET(PORT, HD44780_E);
22
    x = READ(PIN, HD44780_D4);
23
  CLR(PORT, HD44780_E);
24
...
25
  CLR(PORT, HD44780_RW);
26
  if (rs)
27
    SET(PORT, HD44780_RS);
28
  else
29
    CLR(PORT, HD44780_RS);
30
  ASSIGN(PORT, HD44780_D4, n);

Die HD44780_x-Makros sind dabe projektabhängig definiert:
1
#define HD44780_RS A, 6
2
#define HD44780_RW A, 5
3
#define HD44780_E  A, 4
4
/* The data bits have to be not only in ascending order but also consecutive. */
5
#define HD44780_D4 A, 0

Wenn du obiges mal auf besagte Weise durch den Präprozessor schickst,
siehst du, was er da draus zimmert.
OP #4536448
Lesenswert?
• ▲
▼
Walter S. schrieb:
> die beiden anderen gehen IMMER auf LOW
Schau dir die beiden darüber liegenden Makros an - da geht nichts nach 
der ersten Anweisung IMMER auf LOW!

Da diese Anweisung einwandfrei funktioniert, konzentriere ich mich 
lieber auf das was nicht klappt;

__Son´s B. schrieb:
> solch eine Parametrierung machen;
>   #define AUSGANG_SET_HIGH(port,mask) ((port) |= (1<<mask))
>   #define PORT_BATT_OUT(PORTA,PA4)
>   #define BATT_ON (AUSGANG_SET_HIGH(PORT_BATT_OUT))
> Compiler meckert!
Moderator Persönliche Seite #4536506
Lesenswert?
• ▲
▼
__Son´s B. schrieb:
> Schau dir die beiden darüber liegenden Makros an - da geht nichts nach
> der ersten Anweisung IMMER auf LOW!

Doch. Dicker Fehler, den Du nur noch nicht verstanden hast.

Ich vereinfache mal, dann wird es klarer:
1
#define A()       a();b();c();
2
...
3
if (x)
4
   A()

Was macht der Preprocessor draus?
1
if (x)
2
   a();b();c();

Das kann man ohne Code-Änderung umschreiben in:
1
if (x)
2
   a();
3
b();
4
c();
Da ohne geschweiften Klammern nur a() im if-Block steckt, werden b() und 
c() IMMER ausgeführt, egal, ob man es nebeneinander oder untereinander 
schreibt.

Merke: Wenn Du sagst: "Es funktioniert aber", dann heisst das lediglich, 
dass Du es nur im falschen Kontext getestet/überdacht hast - hier 
nämlich für x != 0.
OP #4536588
Lesenswert?
• ▲
▼
Frank M. schrieb:
> Da ohne geschweiften Klammern nur a() im if-Block steckt, werden b() und
> c() IMMER ausgeführt,
Klar, passt doch!
Aber nicht, wie Walter S schrieb; "IMMER auf LOW".

Bsp: Folgend sollen alle 3 Befehle nacheinander ausgeführt werden;
...
#define LED_LOW (AUSGANG_SET_LOW(PORTA,PA5)); 
(AUSGANG_SET_LOW(PORTA,PA6)); (AUSGANG_SET_HIGH(PORTA,PA7))
...
LED_LOW;
...
Somit LED_high aus, LED_mid aus, LED_low ein.
Funktioniert auch Live nach dem 1000-sten mal.

Oder meinst du, dass es eine "unsaubere" Syntax ist?
#4536686
Lesenswert?
• ▲
▼
__Son´s B. schrieb:
> Klar, passt doch!
> Aber nicht, wie Walter S schrieb; "IMMER auf LOW".

dann lies das noch Mal:

Walter S. schrieb:
> nicht der Fehler aber damit wirst Du dir ins Knie schießen:
>
> #define LED_OFF (AUSGANG_SET_LOW(PORTA,PA5));
> (AUSGANG_SET_LOW(PORTA,PA6)); (AUSGANG_SET_LOW(PORTA,PA7))  // alle LEDs
> werden gelöscht
>
> was kommt da raus wenn du
>
> if ( quark )
>  LED_OFF;
>
> schreibst?


das wird zu:
if ( quark )
 LED1 low;

LED2 low;
LED3 low;

2 und 3 werden also IMMER low
Gast #4536814
Lesenswert?
• ▲
▼
__Son´s B. schrieb:
> Mag blöd klingen, aber ich finde blockartige Makros im Header einfacher,
> transparenter und schneller zu erfassen...

Geil,

du bist selbt der beste Gegenbeweis, dass dem nicht so ist. Du siehst 
bei deinem relativ einfachen Code selber nicht schon durch und auch kein 
anderer kann die wirklich helfen, finden aber Fehler, die du nicht 
siehst.

Vieeeeeeel transparenter.
Moderator Persönliche Seite #4536896
Lesenswert?
• ▲
▼
__Son´s B. schrieb:
> Lösungsvorschlag von Jörg Wunsch liest sich (als Anfänger) äusserst
> aufwendig.

Den Aufwand hatte aber nur ich damit, mir das auszudenken. ;-)

Du kannst den Kram einfach in einen Header packen und benutzen.

Der wesentliche Trick ist die doppelte Verschachtelung, also ein
FOO(), welches dann ein FOO_() aufruft.  Der weitere Aufwand, den
ich getrieben habe, dient dann nur dazu, die AVR-Eigenheit der
heiligen Registerdreifaltigkeit (PORTx, PINx, DDRx) so abzubilden,
dass man das „x“ nur an genau einer Stelle im Headerfile schreiben
muss.

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