使用带##连接符的参数宏简化代码,但循环体变量向其传参是无效的
1 简介:背景与目的
近期QB在做嵌入式软件的工作,看这一大坨代码时强迫症发作:
BspTimPwmSetCompareValue(&DRV_M1_TIM, DRV_M1_CHANNEL, 2000 );
BspTimPwmSetCompareValue(&DRV_M2_TIM, DRV_M2_CHANNEL, 3500 );
BspTimPwmSetCompareValue(&DRV_M3_TIM, DRV_M3_CHANNEL, 5000 );
...
BspTimPwmSetCompareValue(&DRV_M12_TIM, DRV_M12_CHANNEL, 18500);
不够简化,通过使用宏能够美化一下代码。不过还是需要直接传递实际数值,不可以用循环传递变换的值,具体看下方的第三部分。
2 参数宏中#和##的使用
关于宏的#和##知识,参考文章为:
link1.
link2.
在此处使用##的连接功能,简洁地替换掉DRV_TIM和DRV_CHANNEL等参数。
2.1 代码应用
探索一下实际应用,简单的案例为:
#include <stdio.h>
#define CNNCT(I) a_##I
#define PUT(C) #C"\n"
int main()
{
int a_1=1;
int a_2=2;
printf("%d\n",CNNCT(1));
printf("%d\n",CNNCT(2));
printf(PUT(CNNCT(1)));
printf(PUT(CNNCT(2)));
}
输出为:
1
2
CNNCT(1)
CNNCT(2)
同理,对于简介部分的代码,可以改写为:
#define PWM(i) BspTimPwmSetCompareValue(&DRV_M##i##_TIM, DRV_M##i##_CHANNEL, 1500 * i + 500);
PWM(1);
PWM(2);
PWM(12);
2.2 无法使用循环加##宏继续简化
简介代码改写后,应用12次就要写12行代码,很自然地会想到使用循环。但是如果像下面这样循环,会报错:
// qbWarning: Wrong Code!
for(int i=1; i<=12; i++)
{
PWM(i);
}
错误提示为:DRV_Mi_TIM和DRV_Mi_CHANNEL未定义。
出现该错误的原因是,宏定义是一种简单的文本替换,而且##也只是简单的文本连接,所以PWM(i)中的i不会被展开为数字,而是直接替换为i。
这一点是由宏和##的工作原理决定的,即使用函数或者变量中转,只要不是实际的数值,也就只是从Mi变成Ma、Mb之类的区别罢了。
#include <stdio.h>
#define CNNCT(I) a_##I
#define PUT(C) #C"\n"
int GetNum(int i)
{
return i;
}
int main()
{
int a_1=1;
int a_2=2;
for(int i=1; i<=2; i++)
{
int x;
x = GetNum(i);
printf(CNNCT(x));
}
}
结果:main.c:2:18: error: ‘a_x’ undeclared (first use in this function); did you mean ‘a_2’? 2 | #define CNNCT(I) a_##I