背景:我无法在此处发布的代码最终将在微控制器上运行,这些宏仅提供了一种通过一个宏定义机制创建多个引脚定义功能的方法。我使用Windows和GCC进行试验。
我试图尽可能抽象出问题。我使用std控制台功能是因为它很方便在控制台窗口中显示它。因此,我还将文件另存为.cpp并在Windows上使用g ++进行编译。
说我像这样设置代码:
#define MACRO2(_x) foo##_x(_x)
#define MACRO1(_x) MACRO2(_x)
#define BAR 3
void fooBAR(int num)
{
std::cout << num << std::endl;
}
如果我运行以下代码(工作示例)
int main()
{
MACRO2(BAR);
return 0;
}
首先将BAR插入## _ x中,从而定义要调用的函数名称,然后将BAR插入为该函数的参数并扩展为其值,因此得到fooBAR(3)。该代码有效,没有错误。
现在,如果我尝试在两者之间添加一个宏(这是我无法进入的现实情况),我的代码如下所示:
int main()
{
MACRO1(BAR);
return 0;
}
但是此代码引发错误,因为当MACRO1(BAR)被MACRO2(BAR)替代时,(BAR)随后被扩展为3,而MACRO2(3)导致未定义的foo3(3),如错误日志所确认:
错误:未在此范围内声明“ foo3”
所以要求是:
- 我需要将BAR传递到MACRO1,并且需要不扩展将其传递到MACRO2
- BAR这个词必须保持原样,我知道我可以使用##来防止它扩展,但是随后我需要在BAR中添加一个字符,函数调用将不再起作用。
是否可以通过某种方式完成此任务?将宏作为参数传递给另一个宏,而没有在过程中扩展初始宏?
答案 0 :(得分:2)
但是此代码引发错误,因为当MACRO1(BAR)得到 用MACRO2(BAR)代替,然后将(BAR)扩展为3,然后 MACRO2(3)导致foo3(3)
是的。这是为您的特定宏集指定的预处理器行为。
被识别后,函数类宏的参数在被替换为宏的替换文本之前会进行完全的宏扩展,除非它们是##
或#
预处理程序运算符的操作数。评估这些运算符的所有外观,然后重新扫描结果文本以及相应的后续文本,以扩展其他宏。
是否可以通过某种方式完成此任务?将宏作为参数传递给另一个宏,而没有在过程中扩展初始宏?
仅当参数是##
或#
运算符的操作数时。后者无济于事,但前者提供了一种解决方法:您可以传递一个附加的空参数,以便可以执行串联操作而无需更改所需的参数:
#define MACRO2(_x) foo##_x(_x)
#define MACRO1(_x,dummy) MACRO2(_x##dummy)
#define BAR 3
int main()
{
MACRO1(BAR,);
return 0;
}
扩展为
int main()
{
fooBAR(3);
return 0;
}
如果您想避免使用多余的逗号,可以通过使MACRO1
可变字母来实现:
#define MACRO2(_x) foo##_x(_x)
#define MACRO1(_x,...) MACRO2(_x##__VA_ARGS__)
#define BAR 3
int main()
{
MACRO1(BAR);
return 0;
}
这会扩展为与另一事物相同的事物。
请注意,这两种方法都可能通过向顶层宏提供不必要的额外参数值而引入错误。人们可能会假设大多数此类错误将在编译时捕获,因为扩展会导致代码损坏,就像在问题中的尝试一样。但是,很难排除这种错误会同时扩展到恰好是有效的错误的可能性的可能性。
答案 1 :(得分:1)
一种实现此目的的方法是稍微更改BAR的定义。
#define MACRO2(_x) foo##_x(_x())
#define MACRO1(_x) MACRO2(_x)
#define BAR() 3