简体   繁体   English

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

[英]How to use switch statement inside a macro in C?

I want to use switch statement inside a macro in C. I have the following code segment: 我想在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);       \

But, this throws an error message, more specificially: 但是,这会抛出一条错误消息,更具体地说:

error: expected expression before 'switch' 错误:'switch'之前的预期表达式

Why is this happening exactly, and what is the proper way to use switch inside a macro in C? 为什么会发生这种情况,在C中使用宏内部切换的正确方法是什么?

you cannot return from a macro and expect that it behaves like a function. 你不能从宏return并期望它的行为像一个函数。 The macro code is expanded literally in your code, so now you have a switch/case & a bunch of return statements in the last parameter of printf ! 宏代码在你的代码中逐字扩展,所以现在你在printf的最后一个参数中有一个switch / case和一堆return语句!

Besides, there's no advantage to use a macro here since you're not using token pasting, stringing or other macros like __FILE__ or __LINE__ in it (as opposed to your THROW_ERROR macro which uses them). 此外,有没有优势,在这里使用宏,因为你不使用标记粘贴,粘连或其他类似的宏__FILE____LINE__在它(而不是你的THROW_ERROR使用它们宏)。

Instead, define a MESSAGE (or better: message ) function: 相反,定义一个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
}

and pass that to printf 并将其传递给printf

As an aside, wrap your THROW_ERROR macro within braces since there are 2 statements: THROW_ERROR ,将THROW_ERROR宏包装在大括号中,因为有两个语句:

#define THROW_ERROR(err)  do { \
    fprintf(stderr, "Error in %s:%d: %s.\n", __FILE__, __LINE__, message(err)); \
    exit(EXIT_FAILURE); } while(0)

else if you do: 否则如果你这样做:

if (fail_code) THROW_ERROR(12);

then only the fprintf statement is executed when an error occurs, and exit happens no matter what! 然后在发生错误时只执行fprintf语句,无论如何都exit

You misunderstand the macro in C. It is only the textual replacement. 你误解了C中的宏。它只是文本的替代品。

You need to use function for it: 你需要使用它的功能:

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 "";
}

you can od course create insane ternary macro: 你可以创建疯狂的三元宏:

#define MESSAGE(err) (err == ERROR_NO_MEMORY ? MSG_NO_MEMORY : err == ERROR_INVALID_INDEX ? MSG_INVALID_INDEX : .... )

With the expression statement extension (implemented on gcc, clang, and tinycc), you can do: 使用表达式语句扩展(在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; })

naturally, this isn't "portable" standard C. Portably you could use either an inline function (pretty much unchanged) or a macro with nested ternary expressions: 当然,这不是“可移植”标准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 )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM