有没有办法控制宏扩展顺序

时间:2010-02-04 18:27:15

标签: c macros c-preprocessor expansion

我希望有人可能知道如何控制/指定宏扩展的顺序。以下是上下文:


// 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被传递给SET宏的参数1。当不用作宏时,此方法可以正常工作:


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,所以在bit-banging时使用它是不可预测的。

我希望有人可能知道如何首先扩展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 个答案:

答案 0 :(得分:4)

在类似函数的宏的扩展中替换参数以一种方式发生。所有在#运算符之后或##的任何一方出现的参数在被替换时都会被完全宏扩展,而不是在扩展类函数宏之前。

这意味着要使一个宏成为两个宏参数,必须在像宏本身扩展所需的函数之前进行一轮宏替换。

这意味着像宏这样扩展到所需函数式宏的第二个函数的解决方案是最简单的解决方案。

即。给出原始的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

你必须使用另一个类似函数的宏来获得你需要的替换。

e.g。

#define SET2(x) SET(x)

然后SET2( STATUS_LED )扩展如下。

SET( LATB , 0x0040; )

然后

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

这是无效的,因为SET宏没有足够的参数;在参数的任何扩展发生之前,参数与参数匹配。我的编译器生成错误;行为没有定义。

SET( STATUS_LED )

答案 1 :(得分:1)

如果根名称始终相同,则可以使用:

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