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

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

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.