mikrocontroller.net

Forum: Compiler & IDEs cpp expand before concatenate, wer kann das Rätsel lösen?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define INSTANCE        USART0
#define FOO             RCU_ ## INSTANCE


expandiert zu RCU_INSTANCE was ich NICHT haben will.
Ich will etwas das zu RCU_USART0 expandiert.
Kann jemand dieses verzwickte Problem lösen?

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

Bewertung
0 lesenswert
nicht lesenswert
Hmm:
$ cat foo.c
#define INSTANCE USART0
#define FOO RCU_ ## USART0

FOO
$ cc -E foo.c
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "foo.c"



RCU_USART0

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Hmm:

Du warst zu schnell, habs nochmal editiert, ich hab eine falsche 
variante gecopypastet. Sorry.

Ich hab schon eine geschlagene Stunde rumexperimentiert mit allen 
möglichen Kombinationen von Strinify und expand makros und bekomms 
einfach nicht hin, dieses komische Verhalten von cpp wird sich mir wohl 
für immer entziehen.

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

Bewertung
0 lesenswert
nicht lesenswert
Was denn nun, ist das da noch nicht das Ergebnis, was du haben willst?

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define CONCAT(a,b)    a ## b
#define CONCAT2(a,b)  CONCAT(a,b)

#define INSTANCE        USART0
#define FOO             CONCAT2(RCU_,INSTANCE)

FOO
ergibt
RCU_USART0

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
>
#define CONCAT(a,b)    a ## b
> #define CONCAT2(a,b)  CONCAT(a,b)
> 
> #define INSTANCE        USART0
> #define FOO             CONCAT2(RCU_,INSTANCE)
> 
> FOO
> ergibt
>
RCU_USART0

Danke!

Warum braucht er zwei davon? Irgendwo stand geschrieben daß 
Makro-Parameter expandiert werden, warum passierts dann nicht schon beim 
ersten Mal? Und wenns beim ersten Mal nicht geht warum dann beim zweiten 
Mal, was ist der Unterschied?

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Warum braucht er zwei davon?

Ich glaub das versteht keiner so genau. Hat irgendwas damit zu tun wann 
genau die Substitution passiert. So richtig durchgeblickt hab ich da 
auch nicht, man fügt immer mehr Evaluations-Ebenen hinzu bis es geht... 
Der korrekte Weg ist es, so wenig wie Möglich mit Makros zu machen und 
stattdessen Klassen, Templates und constexpr zu nehmen...

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

Bewertung
0 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
> Der korrekte Weg ist es, so wenig wie Möglich mit Makros zu machen und
> stattdessen Klassen, Templates und constexpr zu nehmen...

Wenn man aber, wie hier, aus irgendeinem Grund komplette Bezeichner 
synthetisieren muss, geht's nicht groß anders zu machen.

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Wenn man aber, wie hier, aus irgendeinem Grund komplette Bezeichner
> synthetisieren muss, geht's nicht groß anders zu machen.

Ja, dazu müsste man wenn schon das ganze System umstellen, sodass man 
dann RCU.USART0 oder so hat.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt expandiert er zu tief:
#define APB1_BUS_BASE   ((uint32_t)0x40000000U)
#define USART_BASE      (APB1_BUS_BASE + 0x00004400U)
#define USART0          (USART_BASE + 0x0000F400U)

#define P(x,y)          x ## y
#define P2(x,y)         P(x, y)

#define INSTANCE        USART0
#define RCUINST         P2(RCU_, INSTANCE)

RCUINST

bernd@bernd:~ $ cpp foo.c 
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"
# 11 "foo.c"
foo.c:9:28: error: pasting "RCU_" and "(" does not give a valid preprocessing token
 #define RCUINST         P2(RCU_, INSTANCE)
                            ^
foo.c:5:25: note: in definition of macro ‘P’
 #define P(x,y)          x ## y
                         ^
foo.c:9:25: note: in expansion of macro ‘P2’
 #define RCUINST         P2(RCU_, INSTANCE)
                         ^~
foo.c:11:1: note: in expansion of macro ‘RCUINST’
 RCUINST
 ^~~~~~~
RCU_((((uint32_t)0x40000000U) + 0x00004400U) + 0x0000F400U)


So ein Krampf!

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Jetzt expandiert er zu tief:

Oh nein, dann solltest du das ganz anders machen. Nur eine ganz 
bestimmte Evaluations-Tiefe haben zu wollen wird früher oder später 
schief gehen. Mache "#define INSTANCE USART0x" oder so.

Was genau ist denn dieses RCU_USART0?

PS: "P" ist ein nicht so guter Name für ein Makro. Die sollten lang und 
auffällig sein, damit man nicht versehentlich einen C-Bezeichner so 
nennt...

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
> Was genau ist denn dieses RCU_USART0?

Das ist definiert als ein Eintrag in einem enum in dessen numerischem 
Wert eine Registeradresse und eine Bitposition kodiert ist welche sich 
deren rcu_periph_clock_enable() Funktion dann dort wieder rauspopelt um 
irgendwo ein Bit zu setzen um den Takt einzuschalten.

> dann solltest du das ganz anders machen.

Ja. Ich hab mich da verzettelt. Ich wollte das über-elegant lösen, mal 
eben ganz fix in 1 Minute und lande stattdessen für 2 Stunden in der 
Makro-Hölle.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So gehts:
#define APB1_BUS_BASE   ((uint32_t)0x40000000U)
#define USART_BASE      (APB1_BUS_BASE + 0x00004400U)
#define USART0          (USART_BASE + 0x0000F400U)

#define PASTE(x,y)      x ## y
#define PASTE2(x,y)     PASTE(x, y)

#define USART_NUM       0

#define INSTANCE        PASTE2(USART, USART_NUM)
#define RCUINST         PASTE2(RCU_USART, USART_NUM)

INSTANCE
RCUINST

weil da nichts mehr vorkommt das schon definiert ist und das er 
zwischendrin versehentlich expandieren könnte.

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wäre es mit sowas in der Art:
struct UartInstance {
  uint32_t addr;
  uint32_t rcu;
};

static const UartInstance instUART0 = { USART0, RCU_USART0 };
static const UartInstance instUART1 = { USART1, RCU_USART1 };

#define INSTANCE instUART0

...

rcu_periph_clock_enable(INSTANCE.rcu);
Falls C++, dann statt dem Makro:
static constexpr UartInstance& myInstance = instUART0;

Weil das alles konstant ist, wird die (konstante) Variable sowieso 
wegoptimiert.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
> Wie wäre es mit sowas in der Art:struct UartInstance {
>   uint32_t addr;
>   uint32_t rcu;
> };
>
> static const UartInstance instUART0 = { USART0, RCU_USART0 };
> static const UartInstance instUART1 = { USART1, RCU_USART1 };
>
> #define INSTANCE instUART0

Ja, ich glaub sowas in der Art ist noch am saubersten.

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.

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