连接宏没有正确扩展宏参数

时间:2016-06-28 12:45:30

标签: c

感兴趣的宏(IOPORT_CREATE_PIN)是库的一部分,通常可以按需运行。它将特定端口上的特定引脚转换为库内部唯一数字表示。

定义为:

#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))

正常使用

IOPORT_CREATE_PIN(PORTD, 4)
例如,

将IOPORT_和PORTD连接到IOPORT_PORTD。此示例中的IOPORT_PORTD是库的内部定义,它进一步扩展为数值。

但是,由于PORTD(定义为#define PORTD (*(PORT_t *) 0x0660),这里并不真正相关)已经是另一个定义的一部分

#define FLASHPORT PORTD

所以使用

IOPORT_CREATE_PIN(FLASHPORT, 4)

错误地连接到IOPORT_FLASHPORT而不是IOPORT_CREATE_PIN定义中的所需IOPORT_PORTD。

我查看了this interesting answer,并尝试应用一个间接级别,希望宏可以正确扩展,但我无法正确使用。

有没有办法去"包裹"该宏以某种方式使编译器在串联之前将FLASHPORT评估为PORTD?

修改
正如John指出包装的问题所在,FLASHPORT将以递归方式扩展,不仅仅是从FLASHPORT扩展到PORTD,而是扩展到(*(PORT_t *) 0x0660)

有解决方法吗?

2 个答案:

答案 0 :(得分:1)

通常,函数式宏的参数在被替换为宏的替换文本之前本身是宏扩展的。但是,对于作为连接(##)或字符串化(#)运算符的操作数的宏参数,抑制了参数扩展 - 如果要连接或者是连接,则执行双扩展的原因是stringify一个宏的替换值而不是它的名字。

  

我无法更改IOPORT_CREATE_PIN宏。有没有办法以某种方式“包装”该宏以使编译器在串联之前将FLASHPORT唤醒为PORTD?

我的理解是你要定义一个新的宏,例如您可以调用的WRAPPER()代替IOPORT_CREATE_PIN(),其扩展与参数IOPORT_CREATE_PIN()的{​​{1}}相同,并且PORTD, 4时其扩展不会发生变化使用而不是FLASHPORT作为第一个参数。

这是否可行取决于宏参数。一般来说,一个直接的包装器可以满足我的要求:

PORTD

预处理器扩展到:

// For illustrative purposes:
#define IOPORT_PORTD correct!
#define IOPORT_FLASHPORT wrong!

// As specified in the question:
#define FLASHPORT PORTD
#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))

// Wrapper:
#define WRAPPER(port,pin) IOPORT_CREATE_PIN(port, pin)

// Demo:
Direct call:  IOPORT_CREATE_PIN(FLASHPORT, 4)
Wrapped call: WRAPPER(FLASHPORT, 4)
Wrapped call: WRAPPER(PORTD, 4)

这里的问题是,如果Direct call: ((wrong!) * 8 + (4)) Wrapped call: ((correct!) * 8 + (4)) Wrapped call: ((correct!) * 8 + (4)) 本身被定义为一个宏,那么你就被软管了。然后,您无法将PORTD扩展为FLASHPORT;如果PORTD被扩展,那么扩展的结果将在被替换之前以递归方式再次扩展。

替代方法

据我所知或可以确定,不可能为预处理器宏创建通用别名。如果不涉及令牌粘贴或字符串化,您可以按照自己的方式进行操作,只需定义一个宏以扩展为另一个宏的名称,但这与粘贴或字符串化效果不佳。

如果 for-purpose 解决方案可以接受,那么还有其他选择。例如,如果您可以识别可能涉及别名的所有令牌粘贴操作,那么您也可以为粘贴在一起的宏提供别名。在您的情况下,可能如下所示:

FLASHPORT

预处理器将其扩展为

// For illustrative purposes:
#define IOPORT_PORTD correct!
#define PORTD OOPS

// As specified in the question:
#define FLASHPORT PORTD
#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))

// Patch up the token-pasting:
#define IOPORT_FLASHPORT IOPORT_PORTD

// Demo:
Direct call:  IOPORT_CREATE_PIN(FLASHPORT, 4)

当然,这不能很好地扩展,它需要一些知识或研究所涉及的整体宏观集,但它将解决问题中提出的有限范围问题。

答案 1 :(得分:0)

试试这个:

#define MY_IOPORT_CREATE_PIN(port, pin) IOPORT_CREATE_PIN(port ,pin)

然后使用MY_IOPORT_CREATE_PIN而不是IOPORT_CREATE_PIN