C preproc: вставка действительного токена и значения токена

Я работаю с микроконтроллером STM32F1, для которого предоставляется заголовок, определяющий битовые маски и значения для регистров следующим образом:

#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

и т.д.

Что я хочу сделать, так это определить мой множитель PLL как целое число, чтобы я мог использовать его для получения значения часов, т.е. PLLCLK = IN_CLK * PLL_MULT, и вставить значение в RCC_CFGR_PLLMULL, чтобы получить правильные биты настройки. Макросы, которые я обычно использую для этого, следующие:

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

Затем, если я определю SOME_NUM как, скажем, 123:

#define FOO                       APPEND_VAL(BAR, SOME_NUM)

В результате FOO определяется как BAR123. Обычно это работает. Вот в чем проблема: в этом случае RCC_CFGR_PLLMULL является допустимым токеном перед вставкой. Это приводит к тому, что он расширяется при вызове APPEND_VAL, и я получаю что-то вроде ((uint32_t)0x003C0000)123. Я не могу понять, как заставить B расширяться без расширения A, по крайней мере, в GCC. Есть обходные пути, но я ищу чистое решение. Он существует?


person Ben H    schedule 25.08.2014    source источник


Ответы (1)


Я не уверен, что вы считаете "чистым" решением, но это работает для меня и не кажется таким уж плохим:

/* 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))

Вы используете это как, например,

#define FOO RCC_CFGR(PLLMUL, 1)

Вы также можете сделать

#define BAR RCC_CFGR(PLLMUL, )

чтобы определить от BAR до RCC_CFGR_PLLMUL (без хвоста).

Очевидно, это специфично для подмножества возможных целевых макросов, но оно выполняет свою работу и читается без ошибок. Насколько мне известно, нет способа написать полностью общий макрос вставки токенов - те, которые являются наиболее общими, страдают от таких проблем, как описанная вами.

person John Bollinger    schedule 25.08.2014
comment
Это намного лучше, чем куча #ifs, которую я предполагал или пытался запутать токеном, вводя макрос RCC_CFGR ## PLLMULL и т. д. - person Ben H; 26.08.2014
comment
В итоге я сделал это немного по-другому, но в том же духе: #define RCC_CFGR_PLLMULL_HELPER(A) RCC_CFGR_PLLMULL ## A #define RCC_CFGR_PLLMULL_GEN(A) RCC_CFGR_PLLMULL_HELPER(A) #define PLLMULL_BITS RCC_CFGR_PLLMULL_GEN(FOO) Требуется набор макросов для каждого сгенерированного значения, но вся информация хранится в одном месте. - person Ben H; 26.08.2014