简介
使用STM32做运动控制,程序中需要大量使用switch case来控制机械设备的一步步的设备运动.写程序有时会忘记写break,会导致程序的异常执行,查找程序bug也需要花费大量的时间,所以这也是C 语言switch case的致命的缺点。再就是程序大量使用switch case break,经常出现在两行的case和break只夹杂一行有用的逻辑代码,这样就有点主次不分明,程序逻辑会淹没在switch case中.
switch case结构特点和优化
switch case以switch开始,中间包含一些case break,default语句,以}结束。没有使用宏定义的代码:
void ToLimt()
{
switch(L->GetThisStep()):
{
case STEP1:
if(L->IsSensorOn(X001))
{
L->SetActionOk();
}
else
{
L->FindSensor(SM101,3200,X001,STEP2,STEP3);
}
break;
case STEP2:
L->StopSM(SM101);
L->SetActionOk();
break;
case STEP3:
L->FindSensor(SM101,3200,X001,STEP2,STEP_ERROR);
break;
STEP_ERROR:
L->SetErrorInfo("定位电机丢步");
break;
}
}
这里代码模式是:
1.switch里的变量L->GetThisStep()在其它的动作函数是一样的。
2.一个break后面接一个case STEPX:,这在其它动作函数也是这样。
3.以}结束switch。
一个项目可以包含大几十个的动作函数,所以可以把代码模式做成一个代码模板,而这个模板的实现就是使用宏定义,以下是模板的宏定义:
#define START switch(L->GetThisStep()){case STEP1
#define step1 break;case STEP1
#define step2 break;case STEP2
#define step3 break;case STEP3
#define step4 break;case STEP4
#define step_ok break;case STEP_OK
#define step_error break;case STEP_ERROR
#define END break;}
使用宏定义的代码:
void ToLimt()
{
START:
if(L->IsSensorOn(X001))
{
L->SetActionOk();
}
else
{
L->FindSensor(SM101,3200,X001,STEP2,STEP3);
}
step2:
L->StopSM(SM101);
L->SetActionOk();
step3:
L->FindSensor(SM101,3200,X001,STEP2,STEP_ERROR);
step_error:
L->SetErrorInfo("定位电机丢步");
END
}
这样就没有了break.
进一步优化
可以把START宏和函数名合并到一起,END和函数结束的}合并到一起,这样也减少了一对花括号{},也没有了函数。
#define START(x) void x() {switch(L->GetThisStep()){case STEP1
#define END break;}}
进一步优化后的代码:
START(ToLimt):
if(L->IsSensorOn(X001))
{
L->SetActionOk();
}
else
{
L->FindSensor(SM101,3200,X001,STEP2,STEP3);
}
step2:
L->StopSM(SM101);
L->SetActionOk();
step3:
L->FindSensor(SM101,3200,X001,STEP2,STEP_ERROR);
ERROR:
L->SetErrorInfo("定位电机丢步");
END
优化后代码行数更少,看起来也没有了像爬楼梯似的箭头代码.
总结
宏定义在特定领域编程确实可以简化程序的编写和模板化,甚至还能提高程序的运行效率,就像微软MFC的消息映射也使用了大量宏用来替代由于C++虚函数带来的性能开销。宏定义在系统开发中会经常使用到,在不修改编译器的语言语法的前提下,就可以达到编程方式的改变 。