Forum: Compiler & IDEs #Define spinnt oder ich spinne


von John S. (student)


Lesenswert?

Hallo zusammen, ich verzweifele an folgendem Problem, brauche Hilfe:

-----------------
int16_t adcval

#define adcvalMaxY 230
#define adcvalMinY  30

#define MiddleY ((adcvalMaxY - adcvalMinY)/2) + adcvalMinY
//#define MiddleY 130

Wenn ich nun die folgenden Audrücke berechne (mit adcval = 155) dann 
ergibt

(adcval - MiddleY) den Wert  85
(MiddleY - adcval) den Wert -25

Wenn ich nun umkommentiere

//#define MiddleY ((adcvalMaxY - adcvalMinY)/2) + adcvalMinY
#define MiddleY 130

dann ergibt

(adcval - MiddleY) den Wert  25
(MiddleY - adcval) den Wert -25


Was ist denn hier los ??

Ich bin total ratlos!

Grüsse

von John S. (student)


Lesenswert?

Autsch - jetzt habe ich es kapiert ...!

Der Pre-Processor ersetzt den Ausdruck

(adcval - MiddleY)

zu ( adcval - ((230 - 30)/2) + 30  ) ...

und nicht zu

zu ( adcval - ( ((230 - 30)/2) + 30) )

Gefährliche Falle ...!

Danke

von Karl H. (kbuchegg)


Lesenswert?

Yep.
Wie du schon bemerkt hast, ist es immer eine gute Idee
ein Makro zu Klammern wenn es eine Formel darstellen soll.

Aber es gibt noch mehr Fallen mit Makros.

#define DOUBLE(x)  (2 * x)

und jetzt lass mal berechnen

   i = 5;
   j = DOUBLE(i+1)

Das Ergebnis ist nicht 12, sondern 11.
Die Makroexpansion zeigt auch warum. Aus DOUBLE(i+1)
wird
   j = ( 2 * i+1 );
und Aufgrund der Matheregeln wird das als (2*i)+1
gerechnet.

Lösung:
#define DOUBLE(x) ( 2 * (x) )

Das ist aber nicht alles. Es gibt noch mehr. Gefährlich wird
es auch immer dann, wenn ein Makroargument in der Expansion
2 mal vorkommt

#define MAX(x,y) ( (x) < (y) ? (y) : (x) )

und das wendest du mal auf

   i = 5;
   j = 6;
   k = MAX(i++,j++)

an. Welches sind die Werte von i und j nach der Maximumbestimmung?
i hat dann den Wert 6, aber j hat den Wert 8!

Aus diesen Gründen ist man bei Formeln meist mit einer Funktion
auf der besseren Seite

int max( int x, int y )
{
  return x < y ? y : x;
}

Da gibt es keine derartigen überraschenden Effekte. Und da der Compiler
solche Funktionen in den meisten Fällen inlinen wird, hat man auch
keinen Laufzeit-Penalty.

von John S. (student)


Lesenswert?

Hallo,

Dank an Alle, Eure Hinweise waren sehr hilfreich.

Grüsse

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.