Есть ли способ контролировать порядок расширения макроса - PullRequest
3 голосов
/ 04 февраля 2010

Я надеюсь, что у кого-то может быть представление о том, как контролировать / определять порядок расширения макросов. Вот контекст:


// 32 bit increments, processor has registers for set, clear and invert
#define CLR_OFF 1
#define SET_OFF 2
#define INV_OFF 3


#define SET(reg,bits) *((volatile unsigned long*)(& reg+SET_OFF)) = bits
//Now if I use this I can do it quite nicely with
#define STATUS_LED 0x0040;
SET(LATB, STATUS_LED); // LATB is port of the LED.

В последнее время мне пришлось немного переставить аппаратное обеспечение, поэтому я решил сгруппировать информацию о LATB с помощью STATUS_LED примерно так ...


#define STATUS_LED_PORT LATB
#define STATUS_LED_MASK 0x0040;
#define STATUS_LED STATUS_LED_PORT, STATUS_LED_MASK

//And I try to use it via
SET( STATUS_LED );

Но, увы, LATB, 0x0040 передается в аргумент 1 макроса SET. Когда этот метод не используется в качестве макроса, он работает правильно:


inline void SET(u32_t *reg, u32_t bits) { ((volatile u32_t *) (((u32_t)reg) + SET_OFF*4 )) = bits; }
//Change the STATUS_LED macro to
#define STATUS_LED &STATUS_LED_PORT, STATUS_LED_MASK
SET( STATUS_LED); //Works great!

Но, к сожалению, мой компилятор не видит необходимости встроить функцию и заставляет 6 инструкций установить регистр, а не 4, поэтому для использования во время битового разбивки это непредсказуемо.

Я надеюсь, что кто-то может знать, как сначала расширить макрос STATUS_LED, что-то вроде: SET( ##STATUS_LED )

В настоящее время мое решение двигаться дальше - иметь два макроса SET и SETRM (установить регистр, маску), но я чувствую, что должно быть решение, потому что код для SET выглядит следующим образом ...


#define SETRM(reg,bits) ...
#define SET(args) SETRM(args) //WHY WOULD THIS GET EXPANDED HERE??

И, наконец, компилятор моего процессора не поддерживает n-аргументов макроса, я думал, что смогу поиграть с этим, но увы: (.

Большое спасибо за ваше время, и я был бы признателен за любые мысли, я могу двигаться вперед, но было бы намного чище, если бы я мог просто использовать SET везде.

Ответы [ 2 ]

4 голосов
/ 04 февраля 2010

Подстановка параметров при расширении функционально-подобных макросов происходит заданным образом. Все аргументы, которые не появляются после оператора # или любой из сторон ##, полностью раскрываются при замене макроса, а не до раскрытия функционально-подобного макроса.

Это означает, что для того, чтобы один макрос стал двумя аргументами макроса, раунд замены макроса должен произойти до того, как требуемая функция, такая как сам макрос, будет расширена.

Это означает, что решение второй функции, подобной макросу, которая расширяется до нужного функционально-подобного макроса, является самым простым решением.

т.е. учитывая ваше оригинальное SET определение

#define SET(reg,bits) *((volatile unsigned long*)(& reg+SET_OFF)) = bits

и макрос, который расширяется до двух потенциальных аргументов

#define STATUS_LED_PORT LATB
#define STATUS_LED_MASK 0x0040;
#define STATUS_LED STATUS_LED_PORT, STATUS_LED_MASK

Вы должны использовать другой функциональный макрос, чтобы получить нужную вам замену.

, например

#define SET2(x) SET(x)

Затем SET2( STATUS_LED ) расширяется следующим образом.

SET( LATB , 0x0040; )

тогда

*((volatile unsigned long*)(& LATB + 2 )) = 0x0040;

Это неверно, так как недостаточно аргументов для макроса SET; параметры сопоставляются с аргументами до того, как произойдет расширение аргумента. Мой компилятор генерирует ошибку; поведение не определено.

SET( STATUS_LED )
1 голос
/ 04 февраля 2010

Если корневое имя всегда одинаковое, вы можете использовать:

#define SET_COMPOSITE(root) SET(root##_PORT, root##_MASK)
...