Forum: Mikrocontroller und Digitale Elektronik Mehrere Anweisungen hinter einem Define


von Jens K. (mister232)


Lesenswert?

Hallo Leute,

mal me kurze Frage:
Kann man mit einem define mehrere Anweisungen ausführen und wenn ja, wie 
trennt man diese.
Beispiel:
1
#define a1     PORTB |= (1 <<PB1)   PORTA |= (1 <<PA0)

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

Ja kann man. Diese trennt man mit einem Semikolon. Am besten fasst du 
die Anweisungen in einer do-while Schleife zusammen, da sich diese wie 
eine einzige Anweisung verhält:
1
#define a1 do{PORTB |= (1 <<PB1); PORTA |= (1 <<PA0);}while(0)

Hier steht auch noch was dazu:
http://www.mikrocontroller.net/articles/C-Pr%C3%A4prozessor#.23define_f.C3.BCr_eine_Codesequenz

von Thomas E. (thomase)


Lesenswert?

be stucki schrieb:
> Ja kann man. Diese trennt man mit einem Semikolon. Am besten fasst du
> die Anweisungen in einer do-while Schleife zusammen, da sich diese wie
> eine einzige Anweisung verhält:
>
1
#define a1 do{PORTB |= (1 <<PB1); PORTA |= (1 <<PA0);}while(0)

Und wenn es ein bisschen umfangreicher wird:
1
#define a1 do{\
2
               PORTB |= (1 <<PB1);\
3
               PORTA |= (1 <<PA0);\
4
             }while(0)

mfg.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> Und wenn es ein bisschen umfangreicher wird:

Hierbei wichtig: Hinter den \ darf kein weiteres Zeichen stehen, auch 
kein Whitespace (Leerzeichen, Tabs).

von Amateur (Gast)


Lesenswert?

Wird das Schleifenkonstrukt (do-while) wirklich rückstandslos entfernt, 
oder behalte ich eine "unsichtbare" Sprung- bzw. Abfrageanweisung 
zurück?

von Dr. Sommer (Gast)


Lesenswert?

Indem man kein #define verwendet:
1
inline void a1 () {
2
  PORTB |= (1 <<PB1);
3
  PORTA |= (1 <<PA0);
4
}
Keinerlei Performance/Platz-Nachteil ggü. dem #define, vermeidet aber 
all die potentiellen Probleme von Makros und die Frickelei mit do-while 
etc.

von Thomas E. (thomase)


Lesenswert?

Dr. Sommer schrieb:
> Indem man kein #define verwendet:
>
1
inline void a1 () {
2
>   PORTB |= (1 <<PB1);
3
>   PORTA |= (1 <<PA0);
4
> }
Keinerlei Performance/Platz-Nachteil ggü. dem #define, vermeidet
> aber all die potentiellen Probleme von Makros und die Frickelei mit
> do-while etc.

Wenn der Compiler das kann und will, macht er das auch.
In diesem einfachen Beispiel vielleicht sogar  von sich aus ohne 
inline-Deklaration. Aber ein paar Konjunktive gibt es dabei.

mfg.

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

Für meine LCD Routine habe ich das hier verwendet und es funktioniert 
Problemlos:
1
#define LCD_EN LATDbits.LATD0
2
#define Enable Delay10TCYx(1); LCD_EN=1; Delay10TCYx(1); LCD_EN=0; Delay10TCYx(1)

: Bearbeitet durch User
von Ahja..? (Gast)


Lesenswert?

Max H. schrieb:
> Enable

XD, nicht dein Ernst, oder?

von Thomas E. (thomase)


Lesenswert?

Amateur schrieb:
> Wird das Schleifenkonstrukt (do-while) wirklich rückstandslos entfernt,
> oder behalte ich eine "unsichtbare" Sprung- bzw. Abfrageanweisung
> zurück?

Nein das schmeisst der Compiler vollkommen raus. Ist ja auch vollkommen 
sinnlos.

Eigentlich gehört das auch so
#define a1() do{PORTB |= (1 <<PB1); PORTA |= (1 <<PA0);}while(0)

Damit kannst/musst du das Makro wie eine Funktion aufrufen a1();
Und fliegst ohne die do... while in einer if-Abfrage voll auf die 
Fresse.

if(bla) a1(); else a2();

Das jetzt mal für den TO, der sich wahrscheinlich fragt, was das soll.

mfg.

von Max H. (hartl192)


Lesenswert?

Ahja..? schrieb:
> XD, nicht dein Ernst, oder?
Wieso sollte es das nicht sein?

von Dr. Sommer (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Wenn der Compiler das kann und will, macht er das auch.
> In diesem einfachen Beispiel vielleicht sogar  von sich aus ohne
> inline-Deklaration. Aber ein paar Konjunktive gibt es dabei.
Wenn du so paranoid bist schreibst du "__attribute__((always_inline)) 
inline" dran (nur GCC & Clang), dann wird es garantiert ge-inlined und 
ist somit garantiert so effizient wie das Makro, provoziert nur viel 
weniger Probleme.

Thomas Eckmann schrieb:
> Damit kannst/musst du das Makro wie eine Funktion aufrufen a1();
> Und fliegst ohne die do... while in einer if-Abfrage voll auf die
> Fresse.
Warum ein Makro schreiben das wie eine Funktion verwendbar ist, wenn 
man auch einfach eine Funktion schreiben kann?

Max H. schrieb:
> Wieso sollte es das nicht sein?
Weil der Name blöd ist, da weiß keiner was gemeint ist. Was wird denn da 
eingeschaltet, PWM, UART, LED, USB?

von Max H. (hartl192)


Lesenswert?

Dr. Sommer schrieb:
> Weil der Name blöd ist, da weiß keiner was gemeint ist.

Max H. schrieb:
> Für meine LCD Routine [...]

von Thomas E. (thomase)


Lesenswert?

Dr. Sommer schrieb:
> Thomas Eckmann schrieb:
>> Wenn der Compiler das kann und will, macht er das auch.
>> In diesem einfachen Beispiel vielleicht sogar  von sich aus ohne
>> inline-Deklaration. Aber ein paar Konjunktive gibt es dabei.
> Wenn du so paranoid bist schreibst du "__attribute__((always_inline))
> inline" dran (nur GCC & Clang), dann wird es garantiert ge-inlined und
> ist somit garantiert so effizient wie das Makro, provoziert nur viel
> weniger Probleme.
Ich bin nicht paranoid, du A...

> Thomas Eckmann schrieb:
>> Damit kannst/musst du das Makro wie eine Funktion aufrufen a1();
>> Und fliegst ohne die do... while in einer if-Abfrage voll auf die
>> Fresse.
> Warum ein Makro schreiben das wie eine Funktion verwendbar ist, wenn
> man auch einfach eine Funktion schreiben kann?
Hab ich schon geschrieben.

mfg.

von Dr. Sommer (Gast)


Lesenswert?

Max H. schrieb:
> Max H. schrieb:
>> Für meine LCD Routine [...]
Das muss man dann aber immer manuell dazuschreiben. EnableLCD wäre doch 
wesentlich deskriptiver gewesen.

von Max H. (hartl192)


Lesenswert?

Auch wenn euch das Beispiel nicht passt, mehrere Aweisungen hinter einem 
#define sind also problemlos ohne das do while möglich...
Und um das zu zeigen ist der Namen des defines irrelevant...

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Max H. schrieb:
> Auch wenn euch das Beispiel nicht passt, mehrere Aweisungen hinter
> einem
> #define sind also problemlos ohne das do while möglich...
> Und um das zu zeigen ist der Namen des defines irrelevant...
Und was passiert dann?
1
#define Enable Delay10TCYx(1); LCD_EN=1; Delay10TCYx(1); LCD_EN=0; Delay10TCYx(1) 
2
3
int main () {
4
  if (bedingung)
5
    Enable ();
6
}
Und was wird dadraus? (Einrückung zur Verdeutlichung dessen was 
passiert)
1
int main () {
2
  if (bedingung)
3
    Delay10TCYx(1);
4
  LCD_EN=1;
5
  Delay10TCYx(1);
6
  LCD_EN=0;
7
  Delay10TCYx(1) 
8
}
Die Initialisierung erfolgt also immer halb oder ganz, aber nie gar 
nicht. Ob das beansichtigt war?

Noch hässlicher wirds dann wenn man temporäre Variablen und Paramenter 
benötigt...

Um sowas muss man sich keine Gedanken machen wenn man einfach eine 
Funktion verwendet.

von Thomas E. (thomase)


Lesenswert?

Max H. schrieb:
> Auch wenn euch das Beispiel nicht passt, mehrere Aweisungen hinter einem
> #define sind also problemlos ohne das do while möglich...
> Und um das zu zeigen ist der Namen des defines irrelevant...

Weil du Glück hast und das Makro nur auf eine Art und Weise benutzt. Es 
ist dein Makro und nur in deinen Programmen von dir verwendbar.
1
int main(void)
2
{
3
  Enable;
4
  Init();
5
....
6
}

funktioniert.

In diesem speziellen Fall nicht relevant, aber:
1
if(bla) Enable; else(//was weiss ich);

dann steht da plötzlich:
1
if(bla) Delay10TCYx(1); 
2
LCD_EN=1; 
3
Delay10TCYx(1); 
4
LCD_EN=0; 
5
Delay10TCYx(1);
6
else(//was...)

Das Delay wird nur ausgeführt wenn bla true ist, der Rest immer.
Und das else steht ohne if völlig alleine da.

Deswegen gehört die do...while()-Schleife da herum.

Der Name ist trotzdem nicht aussagekräftig.

Makros sind oft Scheisse. Es sei denn, man macht es richtg. Und dann 
kann man noch Stunden darüber diskutieren, ob man die überhaupt 
verwenden soll. Die do...while -Krücke ist für viele ein Argument davon 
abzuraten.

Entweder man benutzt diese Krücke oder man benutzt keine Makros mit 
mehreren Anweisungen. Mit deinem Makro schiesst du dir nur selbst ins 
Knie.
Mit diesem speziellen wahrscheinlich nicht. Aber wenn du deine Makros 
immer so schreibst, mit Sicherheit irgendwann. Und wenn die if-Bedingung 
dann ohne else dasteht, gibt es nicht einmal eine Fehlermeldung.

mfg.

von Jens K. (mister232)


Lesenswert?

Danke für die ganzen Antworten.  Ich denke ich werde es dann mal mit dem 
oberen do/while ausprobieren.

von Haro (Gast)


Lesenswert?

Finde inline Funktionen auch am Schönsten.
Allerdings nur mit Attribut "always inline".

Ich hab mal recht viel mit inline experimentiert und bin zu dem Ergebnis 
gekommen:
Eine Funktion nur als "inline" zu definieren bringt garnichts.
Mit eingeschalteter Optimierung wird der gcc sie sowieso inlinen, wenn 
er der Meinung ist es bringt was.
Und andersherum wird er sie nicht inlinen wenn der Code deswegen zu groß 
wird (z.B. bei mehreren Aufrufen), trotz "inline".

Kann das jemand so bestätigen?

von Dr. Sommer (Gast)


Lesenswert?

Haro schrieb:
> Und andersherum wird er sie nicht inlinen wenn der Code deswegen zu groß
> wird (z.B. bei mehreren Aufrufen), trotz "inline".
>
> Kann das jemand so bestätigen

Leider ja. Es ist sogar noch schlimmer: Selbst wenn der Code durch 
(sogar mehrfach auftretendes) inlinen kleiner würde (durch optimieren 
der Operation und wegfallen des Aufrufs&Parameter-Übergabe -Overhead) 
macht der GCC das nicht immer. Daher muss man sich mit 
__attribute__((always_inline)) behelfen. In C++11 ist sogar eine 
Standard-Notation dafür vorgesehen (um Compiler-unabhängig zu sein) aber 
die unterstützt GCC noch nicht :-/ Aber alles besser als ein Makro, 
insbesondere eines für das es 0 Grund gibt, ein Makro zu sein (wie 
Code-Generierung, impliziter Zugriff auf lokale Variablen (hässlich) 
etc.)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.