cpp expand before concatenate, wer kann das Rätsel lösen?

OP #5821813
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?
Gast #5821818
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...
OP #5821858
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!
Gast #5821863
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...
OP #5821884
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.
OP #5821891
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.
Gast #5821897
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren