我想在C中的宏内部使用switch语句。我有以下代码段:
enum errors {
ERROR_NO_MEMORY,
ERROR_INVALID_INDEX,
ERROR_INVALID_VALUE
};
#define MSG_NO_MEMORY "could not allocate memory"
#define MSG_INVALID_INDEX "index out of bounds"
#define MSG_INVALID_VALUE "invalid value passed as input"
#define MESSAGE(err) \
switch (err) { \
case ERROR_NO_MEMORY: \
return MSG_NO_MEMORY; \
case ERROR_INVALID_INDEX: \
return MSG_INVALID_INDEX; \
case ERROR_INVALID_VALUE: \
return MSG_INVALID_VALUE; \
} \
#define THROW_ERROR(err) \
fprintf(stderr, "Error in %s:%d: %s.\n", __FILE__, __LINE__, MESSAGE(err)); \
exit(EXIT_FAILURE); \
但是,这会抛出一条错误消息,更具体地说:
错误:'switch'之前的预期表达式
为什么会发生这种情况,在C中使用宏内部切换的正确方法是什么?
你不能从宏中return
并期望它的行为像一个函数。宏代码在你的代码中逐字扩展,所以现在你在return
的最后一个参数中有一个switch / case和一堆printf
语句!
此外,在这里使用宏没有任何好处,因为你没有使用标记粘贴,穿线或其他宏,如__FILE__
或__LINE__
(与使用它们的THROW_ERROR
宏相对)。
相反,定义一个MESSAGE
(或更好:message
)函数:
const char *message(int code)
{
switch (err) {
case ERROR_NO_MEMORY:
return MSG_NO_MEMORY;
case ERROR_INVALID_INDEX:
return MSG_INVALID_INDEX;
case ERROR_INVALID_VALUE:
return MSG_INVALID_VALUE;
}
return "unknown error"; // just in case no code matches
}
并将其传递给printf
顺便说一下,将THROW_ERROR
宏包装在括号内,因为有两个语句:
#define THROW_ERROR(err) do { \
fprintf(stderr, "Error in %s:%d: %s.\n", __FILE__, __LINE__, message(err)); \
exit(EXIT_FAILURE); } while(0)
否则如果你这样做:
if (fail_code) THROW_ERROR(12);
然后只有在发生错误时执行fprintf
语句,无论如何都会发生exit
!
你误解了C中的宏。它只是文本的替代品。
你需要使用它的功能:
inline const char *MESSAGE(int code)
{
switch (err)
{
case ERROR_NO_MEMORY:
return MSG_NO_MEMORY;
case ERROR_INVALID_INDEX:
return MSG_INVALID_INDEX;
case ERROR_INVALID_VALUE:
return MSG_INVALID_VALUE;
}
return "";
}
你可以创建疯狂的三元宏:
#define MESSAGE(err) (err == ERROR_NO_MEMORY ? MSG_NO_MEMORY : err == ERROR_INVALID_INDEX ? MSG_INVALID_INDEX : .... )
使用表达式语句扩展(在gcc,clang和tinycc上实现),您可以:
#define MESSAGE(err) \
({ int MESSAGE; switch(err){ \
case ERROR_NO_MEMORY: \
MESSAGE = MSG_NO_MEMORY; \
case ERROR_INVALID_INDEX: \
MESSAGE = MSG_INVALID_INDEX; \
case ERROR_INVALID_VALUE: \
MESSAGE = MSG_INVALID_VALUE; \
}; MESSAGE; })
当然,这不是“可移植”标准C.可以使用内联函数(几乎没有变化)或使用嵌套三元表达式的宏:
#define MESSAGE(err) \
( err==ERROR_NO_MEMORY ? MSG_NO_MEMORY \
: err==ERROR_INVALID_INDEX ? MSG_INVALID_INDEX \
: err==ERROR_INVALID_VALUE ? MSG_INVALID_VALUE \
: 0 )