Laie schrieb:
> #define SETOUT(x) { test |= 1<<x; send(test) }
>
> if(i) SETOUT(1);
> else SETOUT(0);
Das wird allerdings so nicht funktionieren. (Selbst dann nicht, wenn ich
den fehlenden ; im Block ergänze)
Warum nicht?
Sehen wir uns das Ersetzungsergebnis an:1 | if(i) { test |= 1<<1; send(test); };
|
2 | else { test |= 1<<0; send(test); };
|
und jetzt formatieren wir etwas um, wobei wir im Hinterkopf halten, dass
ein {-} Block nicht durch einen ; abgeschlossen wird1 | if(i)
|
2 | {
|
3 | test |= 1<<1; send(test);
|
4 | }
|
5 | ;
|
6 | else
|
7 | {
|
8 | test |= 1<<0; send(test);
|
9 | }
|
10 | ;
|
Das Problem ist der ; hier
1 | if(i)
|
2 | {
|
3 | test |= 1<<1; send(test);
|
4 | }
|
5 | ; <------
|
syntaktisch gehört er nicht zum Block sondern bildet seine eigene, leere
Anweisung.
Mit dieser eigenständigen Anweisung ist aber das vorhergehende if
abgeschlossen. Das nachfolgende else gehört nicht mehr zu diesem if. Das
Ergebnis ist ein Syntax Fehler.
Was war das Programmierer-Problem?
Der Programmierer hat, so wie er es gewohnt ist, hier
ganz automatisch einen ; gesetzt. So wie er es gewohnt ist, wenn da eine
Anweisung oder ein Funktionsaufruf steht.
Nur ist hier dieser ; kontraproduktiv, wie man erkennen kann, wenn man
die Makrosubstitution macht.
Man könnte jetzt natürlich den ; weglassen
1 | if(i) SETOUT(1)
|
2 | else SETOUT(0)
|
aber das
1) sieht seltsam aus
2) funktioniert wiederrum nur dann, wenn man in der Makroersetzung einen
Block hat.
Was man also brauchen würde, das ist ein Text in der Makroersetzung, der
a) als Block fungiert
b) das nachfolgende ; aus dem Quelltext wegkonsumiert.
Und an dieser Stelle taucht dann die Makroversion
1 | #define SETOUT(x) do { test |= 1<<x; send(test); } while(0)
|
auf, die genau das gewünschte leistet.
Sie führt einen Block ein, so dass man mehrere Anweisungen kapseln kann,
ist aber auf der anderen Seite so geschrieben, dass der ; aus dem
Quelltext
1 | if(i) SETOUT(1);
|
2 | else SETOUT(0);
|
einen syntaktischen Zusammenhang mit dem Block kriegt.
Nach Textersetzung (und lesbarer Formatierung) ergibt sich
1 | if(i)
|
2 | do {
|
3 | test |= 1<<1; send(test);
|
4 | } while(0) ;
|
5 |
|
6 | else
|
7 | do {
|
8 | test |= 1<<0; send(test);
|
9 | } while(0) ;
|
und hier sieht man schon, dass alles in Ordnung ist. Der fragliche ;
gehört jetzt zur do-while Loop, ist kein leeres Statement, beendet daher
nicht das if und damit hängt auch nicht das else in der Luft.