How to use switch statement inside a macro in C?

霸气de小男生 提交于 2019-12-13 02:21:20

问题


I want to use switch statement inside a macro in C. I have the following code segment:

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’

Why is this happening exactly, and what is the proper way to use switch inside a macro in C?


回答1:


you cannot return from a macro and expect that it behaves like a function. 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!

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).

Instead, define a MESSAGE (or better: message) function:

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

As an aside, wrap your THROW_ERROR macro within braces since there are 2 statements:

#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!




回答2:


You misunderstand the macro in C. It is only the textual replacement.

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 : .... )



回答3:


With the expression statement extension (implemented on gcc, clang, and tinycc), you can do:

#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:

#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 )


来源:https://stackoverflow.com/questions/52239318/how-to-use-switch-statement-inside-a-macro-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!