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


von Bernd K. (prof7bit)


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
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hmm:
1
$ cat foo.c
2
#define INSTANCE USART0
3
#define FOO RCU_ ## USART0
4
5
FOO
6
$ cc -E foo.c
7
# 1 "foo.c"
8
# 1 "<built-in>"
9
# 1 "<command-line>"
10
# 1 "/usr/include/stdc-predef.h" 1 3 4
11
# 1 "<command-line>" 2
12
# 1 "foo.c"
13
14
15
16
RCU_USART0

von Bernd K. (prof7bit)


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
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von Dr. Sommer (Gast)


Lesenswert?

1
#define CONCAT(a,b)    a ## b
2
#define CONCAT2(a,b)  CONCAT(a,b)
3
4
#define INSTANCE        USART0
5
#define FOO             CONCAT2(RCU_,INSTANCE)
6
7
FOO
ergibt
1
RCU_USART0

von Bernd K. (prof7bit)


Lesenswert?

Dr. Sommer schrieb:
>
1
#define CONCAT(a,b)    a ## b
2
> #define CONCAT2(a,b)  CONCAT(a,b)
3
> 
4
> #define INSTANCE        USART0
5
> #define FOO             CONCAT2(RCU_,INSTANCE)
6
> 
7
> FOO
> ergibt
>
1
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?

von Dr. Sommer (Gast)


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...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Dr. Sommer (Gast)


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.

von Bernd K. (prof7bit)


Lesenswert?

Jetzt expandiert er zu tief:
1
#define APB1_BUS_BASE   ((uint32_t)0x40000000U)
2
#define USART_BASE      (APB1_BUS_BASE + 0x00004400U)
3
#define USART0          (USART_BASE + 0x0000F400U)
4
5
#define P(x,y)          x ## y
6
#define P2(x,y)         P(x, y)
7
8
#define INSTANCE        USART0
9
#define RCUINST         P2(RCU_, INSTANCE)
10
11
RCUINST

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

So ein Krampf!

von Dr. Sommer (Gast)


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...

von Bernd K. (prof7bit)


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.

von Bernd K. (prof7bit)


Lesenswert?

So gehts:
1
#define APB1_BUS_BASE   ((uint32_t)0x40000000U)
2
#define USART_BASE      (APB1_BUS_BASE + 0x00004400U)
3
#define USART0          (USART_BASE + 0x0000F400U)
4
5
#define PASTE(x,y)      x ## y
6
#define PASTE2(x,y)     PASTE(x, y)
7
8
#define USART_NUM       0
9
10
#define INSTANCE        PASTE2(USART, USART_NUM)
11
#define RCUINST         PASTE2(RCU_USART, USART_NUM)
12
13
INSTANCE
14
RCUINST

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

von Dr. Sommer (Gast)


Lesenswert?

Wie wäre es mit sowas in der Art:
1
struct UartInstance {
2
  uint32_t addr;
3
  uint32_t rcu;
4
};
5
6
static const UartInstance instUART0 = { USART0, RCU_USART0 };
7
static const UartInstance instUART1 = { USART1, RCU_USART1 };
8
9
#define INSTANCE instUART0
10
11
...
12
13
rcu_periph_clock_enable(INSTANCE.rcu);
Falls C++, dann statt dem Makro:
1
static constexpr UartInstance& myInstance = instUART0;

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

von Bernd K. (prof7bit)


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.

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.