C 连接宏未正确展开宏参数

C 连接宏未正确展开宏参数,c,C,感兴趣的宏(IOPORT_CREATE_PIN)是库的一部分,通常可以根据需要工作。它将特定端口上的特定管脚转换为库内部唯一的数字表示形式 其定义如下: #define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin)) 通常的用法是 IOPORT_CREATE_PIN(PORTD, 4) 例如,将IOPORT_uu和PORTD连接到IOPORT_uPortd。本例中的IOPORT_PORTD是库的内部定义,进一步扩展为数

感兴趣的宏(IOPORT_CREATE_PIN)是库的一部分,通常可以根据需要工作。它将特定端口上的特定管脚转换为库内部唯一的数字表示形式

其定义如下:

#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))
通常的用法是

IOPORT_CREATE_PIN(PORTD, 4)
例如,将IOPORT_uu和PORTD连接到IOPORT_uPortd。本例中的IOPORT_PORTD是库的内部定义,进一步扩展为数值

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

#define FLASHPORT PORTD
所以使用

IOPORT_CREATE_PIN(FLASHPORT, 4)
错误地连接到IOPORT_FLASHPORT,而不是IOPORT_CREATE_引脚定义中所需的IOPORT_PORTD

我看了一下,并尝试应用一个间接层次,希望宏可以适当地扩展,但我没能正确地进行

是否有一种方法可以“包装”该宏,使编译器在连接之前对FLASHPORT到PORTD求值

编辑:
正如John指出的,包装的问题是,FLASHPORT将被递归地扩展,不仅仅是从FLASHPORT扩展到PORTD,而是扩展到
(*(PORT_t*)0x0660)


有什么解决方法吗?

通常,类似于宏的函数的参数在被替换为宏的替换文本之前都会进行宏扩展。但是,对于作为串联(
#
)或字符串化(
#
)运算符的操作数的宏参数,参数扩展被抑制——如果要串联或字符串化宏的替换值而不是其名称,这就是执行双重扩展的原因

我无法更改IOPORT\u CREATE\u PIN宏。是否有一种方法可以“包装”该宏,使编译器在连接之前将FLASHPORT评估为PORTD

我的理解是,您想定义一个新的宏,例如,
WRAPPER()
,您可以调用它来代替
IOPORT\u CREATE\u PIN()
,它的扩展与
IOPORT\u CREATE\u PIN()
用于参数
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
;如果展开了
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)
预处理器将其扩展为

Direct call: ((correct!) * 8 + (4))
当然,这不能很好地扩展,它需要对所涉及的整个宏集进行一些知识或研究,但它可以解决问题中提出的有限范围问题。

尝试以下方法:

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

然后用我的IOPORT\U CREATE\U PIN代替IOPORT\U CREATE\U PIN

我很困惑。您希望使用的实际宏调用是什么,以及它的扩展是什么?将
(*(PORT_t*)0x0660)
作为标识符名称的一部分是没有意义的。您是否试图在预处理时从内存中获取一个值,以获取一个后缀为该值的名称?这是不可能的。@2501:IOPORT\u CREATE\u PIN宏是库的一部分,可以根据需要工作。它或多或少地将特定端口上的特定管脚转换为库内部唯一的数字表示形式。唯一的问题是,我描述的用例没有将内容连接到一个预期的库定义,例如IOPORT_PORTD,它包含常量来计算结果。@2501:is确实是,正如我在前面的评论中指出的。对不起,如果问题不清楚的话。但是相关的部分是理想的IOPORT_uu和PORTD到IOPORT_PORTD的连接,我可能无法清楚地进行沟通。注意:如果您刚刚硬编码了所有这些宏,那么您将在很久以前完成。元编程并不总是最好的选择。正如我在对你的问题的评论中提到的,这个解决方案已经在相关的点上找到了(事实上,我没有意识到的是FLASHPORT将被递归地扩展)。我认为包装只是减少了一个级别的扩展。这就是为什么Grzegorz的建议(实际上这是我在阅读了我在问题中提供的链接后尝试的第一件事)不起作用的原因。所以我想不可能实现我想要的?我试图对这个问题做一些澄清,因为似乎对实际目标有很多困惑。@Rev1.0,是的,这个问题很困惑。其中有些方面尚不清楚。尽管如此,我还是补充了一些评论,并描述了可能的替代方法。如有必要,请询问“不清楚的方面”。但从你的备选方案来看,我想你明白我的意思了。即使它需要在配置头中定义第二个稍微冗余的定义,它也比必须在sour中进行更改更清晰、更容易修改