最初这必须是另一个问题的最后一段(this one),但我注意到主题不是那么相似,因此我想发布另一个问题。
我要做的是创建一个自动化系统,以简单的方式编译一些操作。
例如,而不是写
switch (var)
{
case SM_1:
printf("Case 1");
break;
case SM_2:
printf("Case 2");
break;
case SM_3:
printf("Case 3");
break;
}
我会更容易写出像
这样的东西#define CASES
#define CreateCaseX(s,l) CASES += \
case s: \
printf(l); \
break;
CreateCaseX(SM_1, "Case 1")
CreateCaseX(SM_2, "Case 2")
CreateCaseX(SM_3, "Case 3")
...
switch(var)
{
CASES
}
我不希望CASES +=
语句实际工作,但是......是否有一些类似的构造我可以在预处理器中使用来添加一些动作(函数调用,切换案例......)列表,然后让它一次写出来?
我正在写一个简单的状态机。每当我添加状态时,我都必须执行不同的代码修改,例如
例如,我可以在我的文件中包含这些行:
enum {
SM_Case_1,
SM_Case_2,
SM_Case_3
} currentState;
void printState()
{
switch (currentState)
{
case SM_Case_1:
printf("State 1");
break;
case SM_Case_2:
printf("State 2");
break;
case SM_Case_3:
printf("State 3");
break;
}
}
void executeAction()
{
switch (currentState)
{
case SM_Case_1:
// Do nothing
break;
case SM_Case_2:
globalVariable += 10;
break;
case SM_Case_3:
printf("Error");
break;
}
}
我认为有一个宏处理这个问题会更容易(也更容易维护),例如:
#define ENUMS
#define NAMES_CASES
#define ACTION_CASES
#define CreateState(s,l,a) \
ENUMS += s, \
NAMES_CASES += case s: printf(l); break; \
ACTION_CASES += case s: a; break;
CreateState(SM_Case_1,"State 1",{})
CreateState(SM_Case_2,"State 2",globalVariable += 10)
CreateState(SM_Case_3,"State 3",printf("Error"))
enum {
ENUMS
} currentState;
void printState()
{
switch (currentState)
{
NAMES_CASES
}
}
void executeAction()
{
switch (currentState)
{
ACTION_CASES
}
}
我注意到编写一个可行的语法很棘手,所以可能这样的技术不存在,但是......如果有的话,知道它是有用的。
答案 0 :(得分:5)
在宏中没有通用的方法来累积字符串,但是您可以通过将宏调用序列构建为宏来有效地定义列表。这必须在一个部分完成,但似乎这适用于你的例子。
构建完列表后,您可以多次使用它以达到不同的目的。这种技术通常被称为X macros。
这是一个简单的例子。 (我个人更喜欢将宏名称传递给X宏的样式,而不是像维基百科文章中那样对宏名称X
进行硬编码。)
// Make the list (I added semicolons to the actions.)
#define STATES(X) \
X(SM_Case_1,"State 1",{}) \
X(SM_Case_2,"State 2",globalVariable += 10;) \
X(SM_Case_3,"State 3",printf("Error");)
//...
#define ENUM(S, L, A) S,
enum {
STATES(ENUM)
} currentState;
#undef ENUM
// ...
#define CASE(S, L, A) case S: printf("%s", L); break;
void printState() {
switch (currentState) {
STATES(CASE);
}
}
#undef CASE
// ...
#define CASE(S, L, A) case S: { A } break;
void executeAction() {
switch (currentState) {
STATES(CASE);
}
}
#undef CASE
请注意,后两个节很相似,可以在宏中包含:
#define SWITCH_FUNC(NAME, CASE) \
void NAME() { switch (currentState) { STATES(CASE); } }
此外,您可以使用标记连接和字符串化将列表简化为两个参数而不是三个:
#define STATES(X) \
X(State_1, {}) \
X(State_2, globalVariable += 10;) \
X(State_3, printf("Error");)
#define CONCAT_(A, B) A##B
#define STRINGIFY_(S) #S
#define CASENAME(S) CONCAT_(SM_, S)
#define ENUM(S,A) CASENAME(S),
#define PRINT_CASE(S,A) case CASENAME(S): printf("%s", STRINGIFY_(S)); break;
#define ACTION_CASE(S,A) case CASENAME(S): { A } break;
(Live on coliru,虽然预处理器输出有点难以阅读)
有时,您会希望使用预处理器条件来控制是否将单个项目放入列表中。请参阅this answer的第二部分,以获得完成此任务的绝佳技巧。
答案 1 :(得分:2)
你不能不知道这个有效代码的区别是什么?
ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);
只需使用3个宏定义#include <stdio.h>
#define SM_1 1
#define SM_2 2
#define SM_3 3
#define CreateCaseX(s,l) case s: \
printf(l); \
break
#define CASES \
CreateCaseX(SM_1, "Case 1"); \
CreateCaseX(SM_2, "Case 2"); \
CreateCaseX(SM_3, "Case 3")
void test(int var)
{
switch(var)
{
CASES;
}
}
即可。这是您可以获得的最接近的列表。