Forum: Compiler & IDEs C-Präprozessor: Frgae zum Auflösen von Makros


von Oliver S. (z0ttel)


Lesenswert?

Hallo Allerseits,

ich habe ein Makro in der Form
1
#define SET_PIN(port, pin) (port) |= (1 << (pin));
 definiert.

Verwende ich das Makro folgendermaßen
1
/* ... some code ... */
2
SET_PIN(PORTA, PA0)
3
/* ... some code ... */

funktioniert es auch wie gewollt. Der Einfachheit halber möchte ich die 
Parameter nun ebenfalls als Makro übergeben:
1
#define SET_PIN(port, pin) (port) |= (1 << (pin));
2
#define PIN_LED (PORTA, PA0)
3
/* ... some code ... */
4
SET_PIN(PIN_LED)
5
/* ... some code ... */

dieses schlägt jedoch fehl, da an das Makro nur ein (anstatt zwei) 
Parameter übergeben wird. Anscheinend wird SET_PIN vor PIN_LED 
substituiert.

Lässt sich das Verhalten irgendwie so ändern, dass das Makro innerhalb 
der Klammern vor dem äusseren makro aufgelöst wird?

Am Rande: ich möchte dieses Funktionalität bewusst mit Makros (und nicht 
Funktionen) implementieren. Ein "Inlinen" der Funktion hat nicht immer 
zum gewünschten Resultat geführt, manchmal scheint der Compiler trotzdem 
einen Funktionsaufruf einzufügen.

von Dr. Sommer (Gast)


Lesenswert?

Oliver S. schrieb:
> Ein "Inlinen" der Funktion hat nicht immer
> zum gewünschten Resultat geführt, manchmal scheint der Compiler trotzdem
> einen Funktionsaufruf einzufügen.
Das lässt sich (zumindest beim GCC) so beheben:
1
inline __attribute__((always_inline)) void setPin () {
Immer noch weniger hässlich als Makros.

von Nase (Gast)


Lesenswert?

Oliver S. schrieb:
> ich habe ein Makro in der Form
> #define SET_PIN(port, pin) (port) |= (1 << (pin));

Mach besser
1
#define SET_PIN(port, pin) do { (port) |= (1 << (pin)); } while(0)
draus.

Außerdem hilft dir Indirektion:
1
#define SET_PIN2(port, pin) do { (port) |= (1 << (pin)); } while(0)
2
#define SET_PIN(x) SET_PIN2(x)
3
4
#define PIN_LED PORTA, PA0
5
SET_PIN(PIN_LED)

von Stapel (Gast)


Lesenswert?

Oliver S. schrieb:
> Parameter nun ebenfalls als Makro übergeben:
> #define SET_PIN(port, pin) (port) |= (1 << (pin));
> #define PIN_LED (PORTA, PA0)
> /* ... some code ... */
> SET_PIN(PIN_LED)
> /* ... some code ... */
> dieses schlägt jedoch fehl, da an das Makro nur ein (anstatt zwei)
> Parameter übergeben wird. Anscheinend wird SET_PIN vor PIN_LED
> substituiert.

Hast du mal die Reihenfolge geändert?
1
#define PIN_LED (PORTA, PA0)
2
#define SET_PIN(port, pin) (port) |= (1 << (pin));

von Toxic (Gast)


Lesenswert?

https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html
https://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html#Argument-Prescan
https://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html#Macro-Pitfalls


===============
The number of arguments you give must match the number of parameters in 
the macro definition. When the macro is expanded, each use of a 
parameter in its body is replaced by the tokens of the corresponding 
argument. (You need not use all of the parameters in the macro body.)
===============

von Schaulus Tiger (Gast)


Lesenswert?

Oliver S. schrieb:

> Am Rande: ich möchte dieses Funktionalität bewusst mit Makros (und nicht
> Funktionen) implementieren. Ein "Inlinen" der Funktion hat nicht immer
> zum gewünschten Resultat geführt, manchmal scheint der Compiler trotzdem
> einen Funktionsaufruf einzufügen.

Wenn sonst alles gleich bleibt, sollte die Optimierung -Os 
Funktionsaufrufe produzieren, im Gegensatz zu -O2.

Wenn die Funktion ohne "static" deklariert ist, muss sie als echte 
Funktion existieren. Dann wäre es ja Flash-Verschwendung, sie nochmal 
inline ein zu bauen. Und dann wieder, wenn wirklich auf Geschwindigkeit 
optimiert wird und die Funktion nur 3 Befehle enthält...

von (prx) A. K. (prx)


Lesenswert?

Schaulus Tiger schrieb:
>> Am Rande: ich möchte dieses Funktionalität bewusst mit Makros (und nicht
>> Funktionen) implementieren. Ein "Inlinen" der Funktion hat nicht immer
>> zum gewünschten Resultat geführt,

In GCC kann mit dem Attribut always_inline zusätzlich zu inline das 
Inlining erzwingen.

> Wenn sonst alles gleich bleibt, sollte die Optimierung -Os
> Funktionsaufrufe produzieren, im Gegensatz zu -O2.

Die Entscheidung, ob inlined wird oder nicht, wird zwar von der Art der 
Optimierung beeinflusst, ist aber komplexer als dieses simple Schema.

von Markus F. (mfro)


Lesenswert?

das Funktionsattribut _flatten_ bringt gcc dazu, in die betreffende 
Funkion soviel wie möglich per inline "reinzuziehen". Unabhängig davon, 
ob die aufgerufenen Funktionen selbst inline deklariert sind und auch 
(zumindest bei meinen Versuchen, dokumentiert ist das m.W. nicht) 
unabhängig von der Optimierung.

Natürlich muß der entsprechende Code von der Funktion aus sichtbar sein.

Damit kann man auch in per -Os übersetzten Modulen einzelne Funktionen 
gezielt "schnell" machen.

von Ausgeloggt (Gast)


Lesenswert?

Oliver S. schrieb:
>
1
> #define SET_PIN(port, pin) (port) |= (1 << (pin));
2
> #define PIN_LED (PORTA, PA0)
3
> /* ... some code ... */
4
> SET_PIN(PIN_LED)
5
> /* ... some code ... */
6
>
> dieses schlägt jedoch fehl, da an das Makro nur ein (anstatt zwei)
> Parameter übergeben wird. Anscheinend wird SET_PIN vor PIN_LED
> substituiert.

Nein, Der Präprozessor substituiert PIN_LED inklusive Klammern!
1
SET_PIN(PIN_LED) ==> SET_PIN((PORTA, PA0))

So sollte es also funktionieren:
1
#define SET_PIN(port, pin) ...
2
#define PIN_LED PORTA,PA0
3
SET_PIN(PIN_LED)

von Ausgeloggt (Gast)


Lesenswert?

Oh, und ich hab auch mal diese Variante gesehen:
1
#define SET_PIN(port, pin) ...
2
#define PIN_LED (PORTA,PA0)
3
4
SET_PIN PIN_LED
*schauder!*

von Tom (Gast)


Lesenswert?

Was ist an Funktionen eigentlich so schlimm, dass man sich sowas bauen 
muss? Ein gefühltes diffuses Optimierungsbedürfnis? Fricklerstolz und 
Mittelfinger gegen die abgehobenen Richtig-und-schön-Programmierer?

von Ausgeloggt (Gast)


Lesenswert?

Tom schrieb:
> Was ist an Funktionen eigentlich so schlimm, dass man sich sowas bauen
> muss?

Nichts, ausser ein bisschen Performance falls der Compiler kein inline 
unterstützt. Es gibt sogar Coding Standards die der Benutzung solcher 
Makros mit Parametern (Function-like macros) unterbinden - z.B. MISRA C.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Ausgeloggt schrieb:
> Nichts, ausser ein bisschen Performance falls der Compiler kein inline
> unterstützt.

...im GCC-Forum!?

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.