我想在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); \
但是,这会抛出一条错误消息,更具体地说:
错误:“切换”之前的预期表达方式
为什么会这样呢?在C宏中使用switch的正确方法是什么?
答案 0 :(得分:3)
您不能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
宏用大括号括起来,因为有2条语句:
#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
!
答案 1 :(得分:1)
您误解了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 : .... )
答案 2 :(得分:1)
使用表达式语句扩展名(在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 )