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