mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Wer kann mir dieses Define erklären?


Autor: Hans R. (hansrichter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey Leute,

wer wäre mal so nett und erklärt mir das folgende #define?

#define TEST()  (PORTD &= ~(1<<PD1)); (PORTD |= ( (1<<PD3) | (1<<PD7) ))

Die Trennung duch Semikolom im define ist mir unbekannt. Ich würde 
denken, das es folgendes bedeutet:


PD1 auf 0 setzen, ansonsten nichts verändern

und

PD3 und PD7 auf 1 setzen, ansonsten nichts verändern.

Richtig soweit?

Wie wäre es aber, wenn ich nicht nur an PORTD etwas verändern will 
sondern auch an PORTB?

Kann ich dann in einem #define in einer Zeile so schreiben (sofern meine 
Interpretation überhaupt richtig ist):

#define TEST()  (PORTD &= ~(1<<PD1)); (PORTD |= ( (1<<PD3) | (1<<PD7) 
)); (PORTB |= (1<<PB3))

?

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans R. schrieb:

> Die Trennung duch Semikolom im define ist mir unbekannt.

Nun, die rechte Seite eines #define ist ja weiter nichts als das,
was bei Aufruf des Makros dann als Text stattdessen eingesetzt
wird.  Insofern kannst du natürlich dort erst einmal beliebige
Zeichen stehen haben.

Allerdings ist ein Semikolon innerhalb runder Klammern in der Tat
seltsam, und in vielen Fällen dürfte die Verwendung dieses Makros
wohl zu einem Syntaxfehler führen.

> Ich würde
> denken, das es folgendes bedeutet:

Das war wohl die Intention.

Besser würde man es so schreiben:
#define TEST() do { PORTD &= ~(1<<PD1)); (PORTD |= ( (1<<PD3) | (1<<PD7) ); } while(0)

Diese do … while(0)-Konstruktion erscheint auf den ersten Blick
seltsam, hat aber den Vorteil, dass sie syntaktisch in der Tat ein
einziges Statement ist.  Da sie einen Block innerhalb geschweifter
Klammern beinhaltet, darf man darin wiederum weitere Statements mit
Semikolon trennen.

Der Vorteil dieses Konstrukts kommt vor allem dann zum Tragen, wenn
man schreiben möchte:
if (bedingung)
  TEST();
else
  MACHWASANDERES();

> Wie wäre es aber, wenn ich nicht nur an PORTD etwas verändern will
> sondern auch an PORTB?

Welche Sub-Statements man da mit Semikolons trennt, ist dem Compiler
am Ende wurscht.

Autor: Huh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach dem Semikolon ist ein Kommentar...

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Huh schrieb:
> Nach dem Semikolon ist ein Kommentar...

In welcher Programmiersprache sollte denn eine öffnende runde
Klammer, die einem Semikolon folgt, einen Kommentar einleiten?

In C jedenfalls wohl nicht.

Autor: W.A. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans R. schrieb:
> wer wäre mal so nett und erklärt mir das folgende #define?
>
> #define TEST()  (PORTD &= ~(1<<PD1)); (PORTD |= ( (1<<PD3) | (1<<PD7) ))

Der Präprozessor ersetzt auf Grund dieser /define/-Direktive in deinem 
Quelltext
TEST()
 durch
(PORTD &= ~(1<<PD1)); (PORTD |= ( (1<<PD3) | (1<<PD7) ))
bevor er an durch den Compiler geschickt wird.

Autor: Huh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Allerdings ist ein Semikolon innerhalb runder Klammern in der Tat
> seltsam,

Ich denke, daß es NICHT innerhalb einer Klammer ist...
Hans R. schrieb:
> #define TEST()  (PORTD &= ~(1<<PD1));

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Spätestens, wenn das Macro so verwendet wird
if (condition)
  TEST();
 
macht man ne Bauchlandung.  Falls eine inline-Funktion wie
 
static inline void __attribute__((__always_inline__))
TEST (void)
{
  PORTD &= ~(1<<PD1);
  PORTD |= (1<<PD3) | (1<<PD7);
}
 
ausscheidet, wählt man besser folgendes Konstrukt:
 
#define TEST()                    \
  do {                            \
    PORTD &= ~(1<<PD1);           \
    PORTD |= (1<<PD3) | (1<<PD7); \
  } while (0)

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Huh schrieb:
> Ich denke, daß es NICHT innerhalb einer Klammer ist.

OK, verzählt.

Aber der Rest passt schon, und Johann tutet ja ins gleiche Horn –
wobei er völlig Recht hat, dass eine inline-Funktion übersichtlicher
ist.

Autor: Huh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Huh schrieb:
>> Ich denke, daß es NICHT innerhalb einer Klammer ist.
>
> OK, verzählt.
>
> Aber der Rest passt schon, und Johann tutet ja ins gleiche Horn –
> wobei er völlig Recht hat, dass eine inline-Funktion übersichtlicher
> ist.

Das stimmt. Da hat er recht.

Autor: Hans R. (hansrichter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich das so schreibe, dann meckert der GCC-Compiler:

Error    expected identifier or '(' before 'do'
Error    expected identifier or '(' before 'while'


#define Test()
do
{
  PORTD &= ~(1<<PD2);
  PORTD |= (1<<PD3);
        PORTB |= (1<<PB3);
} while (0)

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans R. schrieb:
> Wenn ich das so schreibe, dann meckert der GCC-Compiler:

Kann nicht sein.  Beim #define kann er noch gar nicht meckern.

Entscheidend ist die Stelle, an der du "Test()" verwendest, aber die
hast du uns nicht gezeigt.

Autor: snorlax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans R. schrieb:
> Wenn ich das so schreibe, dann meckert der GCC-Compiler:

\ vergessen

Autor: Joe F. (easylife)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> ausscheidet, wählt man besser folgendes Konstrukt:

wozu das do und while(0)?
die geschweiften klammern reichen aus.

: Bearbeitet durch User
Autor: snorlax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joe F. schrieb:
> wozu das do und while(0)?
> die geschweiften klammern reichen aus.

Um das ; in Test(); zu legitimieren.
Ansonsten klappt der if else Fall nicht.

Autor: Joe F. (easylife)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja, ok, aber wer vor 'else' ein semikolon setzt ist selbst schuld.
mit deinem makro funktioniert dafür der fall ohne 'else' nicht bzw. nur 
mit ';;'

: Bearbeitet durch User
Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joe F. schrieb:
> ja, ok, aber wer vor 'else' ein semikolon setzt ist selbst schuld.

Aha.  Du meinst also
if (cond)
  a = sin(x)
else
  a = cos(x);

wäre legales C?

Wenn du das nicht meinst, dann solltest du wohl deine obige Aussage
nochmal überdenken …

Nimm's einfach, wie es ist: dieser do…while(0)-Konstrukt im Body eines
Makros ist das übliche Mittel dafür, dass man den Makro wie einen
normalen Funktionsaufrauf in einer if-Anweisung benutzen kann.

Im übrigen würde es bei dem ganz oben gezeigten Makro in diesem Falle
auch gar nicht helfen, wenn man das Semikolon vom Aufrufer des Makros
in den Makro verlagert: nach dem if steht dann trotzdem nur eine
Anweisung, obwohl zwei gewünscht sind.

Ja, immer geschweifte Klammern nach einem if schreiben ist defensiv
und hilft ebenfalls (und ist daher in manchen Programmierrichtlinien
vorgeschrieben), aber die do…while(0)-Variante hilft eben auch dann,
wenn derjenige, der das if schreibt, sowas nicht von sich aus tut.

Und weil's noch nicht oft genug geschrieben worden ist: eine
inline-Funktion benimmt sich immer syntaktisch wie eine Funktion,
auch ohne derartig seltsam anmutende Tricks, und sie ist auch noch
in der Regel einfacher zu lesen als ein verzwackter Makro.  Man sollte
einer solchen also nach Möglichkeit den Vorzug gegeben.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.