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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在C中使用宏内的switch语句?相关的知识,希望对你有一定的参考价值。

我想在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.
", __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.
", __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 )

以上是关于如何在C中使用宏内的switch语句?的主要内容,如果未能解决你的问题,请参考以下文章

VIM - 宏内的多次搜索破坏了预期的逻辑

C语言switch case后如何执行多条命令

无法从循环内的switch语句接收值

如何在switch语句中选择一个值范围

C语言中if和switch有啥区别?

c语言switch语句中default是啥意思?