如何在C中的宏内使用switch语句?

时间:2018-09-08 20:51:37

标签: c switch-statement c-preprocessor

我想在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的正确方法是什么?

3 个答案:

答案 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 )