ctokenc-preprocessorstm32pasting

C preproc: pasting valid token and value of a token


I am working with an STM32F1 microcontroller, for which a header is provided that defines bit masks and values for registers as follows:

#define RCC_CFGR_PLLMULL    //Mask of PLL multiplier setting bits
#define RCC_CFGR_PLLMULL1   //Value of PLL multiplier bits for PLL x1
#define RCC_CFGR_PLLMULL2   //Value of PLL multiplier bits for PLL x2
#define RCC_CFGR_PLLMULL3   //Value of PLL multiplier bits for PLL x3

etc etc.

What I want to do is define my PLL multiplier as an integer so I can use it to derive the clock value - ie PLLCLK = IN_CLK * PLL_MULT - and paste the value onto RCC_CFGR_PLLMULL to obtain the correct setting bits. The macros I would normally use for this are as follows:

#define APPEND_VAL_HELPER(A, B)   A##B
#define APPEND_VAL(A, B)          APPEND_VAL_HELPER(A,B)

Then if I define SOME_NUM as, say, 123:

#define FOO                       APPEND_VAL(BAR, SOME_NUM)

Results in the FOO defining as BAR123. Normally this works. Here's the problem: in this case, RCC_CFGR_PLLMULL is a valid token before being pasted. This results in it expanding in the invocation of APPEND_VAL and I get something like ((uint32_t)0x003C0000)123. I can't figure out how to get B to expand without also expanding A, at least in GCC. There are workarounds to this but I'm looking for a clean solution. Does it exist?


Solution

  • I'm not sure what you would consider a "clean" solution, but this works for me and doesn't seem too bad:

    /* target header */
    #define RCC_CFGR_PLLMULL         0x003C
    #define RCC_CFGR_PLLMULL1        0x0003
    
    /* pasting macros */
    #define APPEND_VAL_HELPER(A, B)  A ## B
    #define APPEND_VAL(A, B)         APPEND_VAL_HELPER(A, B)
    #define RCC_CFGR(T, N)           APPEND_VAL(RCC_CFGR_, APPEND_VAL(T, N))
    

    You use that as, for example,

    #define FOO RCC_CFGR(PLLMUL, 1)
    

    You can also do

    #define BAR RCC_CFGR(PLLMUL, )
    

    to define BAR to RCC_CFGR_PLLMUL (no tail).

    Obviously, this is specific to a subset of possible target macros, but it does the job and reads cleanly. To the best of my knowledge there is no way to write a fully general token-pasting macro -- those that are most general suffer from issues such as the one you described.