【问题标题】:How to convert a variable argument function into a macro?如何将可变参数函数转换为宏?
【发布时间】:2010-11-22 14:34:23
【问题描述】:

我有一个可变参数函数,它在我的应用程序中打印错误消息,其代码如下:

void error(char *format,...)
{   va_list args;
    printf("Error: ");
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    printf("\n");
    abort(); 
}

该函数用于错误情况如下:

error("invalid image width %d and image height %d in GIF file %s",wid,hei,name);

error() 函数从不同的地方以不同的参数调用(可变参数函数)。

函数方法运行良好。

现在,如果我必须将此函数转换为宏,我该怎么做?我试着这样做:

#define error(format)  {va_list args;\
    printf("Error: ");\
    va_start(args, format);\
    vfprintf(stderr, format, args);\
    va_end(args);\
    printf("\n"); abort()}

但这并不能正确打印参数。

上面的宏定义有什么问题?

解决方法是什么?

【问题讨论】:

    标签: c function macros variadic-functions


    【解决方案1】:

    如果您的编译器支持 ISO 风格的可变参数宏,您可以这样定义宏:

    #define error(...) \    
        fprintf(stderr, "Error: ");   \
        fprintf(stderr, __VA_ARGS__); \
        fprintf(stderr, "\n"); \
        abort();
    

    或者,如果您使用的是 GCC,也可以使用 GNU 风格的可变参数宏:

    #define error(format, args...) \    
        fprintf(stderr, "Error: ");   \
        fprintf(stderr, format , ## args); \
        fprintf(stderr, "\n"); \
        abort();
    

    欲了解更多信息,请参阅http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

    更新

    如果你的编译器不支持可变参数宏,一个(糟糕的?)替代方法是坚持va_list in function 方法。如果您希望定义驻留在头文件中,那么也许是静态内联函数?

    static inline void error(const char *fmt, ...) {
    #define PRINT_ERROR
        va_list args;
        fprintf(stderr, "Error: "); 
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
        fprintf(stderr, "\n");
        abort();
    #endif
    }
    

    【讨论】:

    • @shawnchin:谢谢。我在 MSVC6.0、MSVS-2005 编译器中尝试过,它似乎不支持可变参数宏。我猜 GCC 支持,但是你知道任何基于 Windows 的编译器支持这个吗?
    • @goldenmean:这个网站说 ISO 风格的 Variadic 宏是在 MSVS-2005 Visual C++ (msdn.microsoft.com/en-us/library/ms177415(VS.80).aspx) 中引入的
    • @shawnchin:是否有任何特殊的 MSVisual Studio 项目选项需要设置以使编译器能够编译此可变参数宏。我尝试设置几个选项(例如将代码编译为 C++)是否有任何宏强制编译器接受这些可变参数宏扩展(它们是 C99 扩展)?
    • 当我浏览其他 SO 帖子时,我可以通过此链接:stackoverflow.com/questions/139479/… 表示 MSVS2005 可能不支持 C99 功能(Varuiadic 宏是 C99 功能之一)。
    • 恐怕我没有安装 MSVS 来测试它。但是,谷歌搜索结果和这个 SO 帖子 (stackoverflow.com/questions/65037/…) 声称从 VC++ 2005 开始确实支持可变参数宏。
    【解决方案2】:

    这是article with some examples on variable arguments used in a macro。看起来它应该做你正在寻找的东西。您可以在宏中使用__VA_ARGS__

    您使用的是哪个编译器?

    【讨论】:

    • 看起来它可以正常工作。但是为什么用宏替换一个非常好的函数调用呢?在这种情况下,内联代码不会对性能或任何事情产生任何影响。它只是把一些像样的代码变成垃圾代码
    【解决方案3】:

    宏不(还?)支持可变参数,无论如何,使用va_list 在这里不起作用,它只适用于可变参数函数

    你为什么要用宏替换函数(根据你的说法,它工作得很好)?

    【讨论】:

      【解决方案4】:

      有一个通用的扩展可以做你想做的,只需写:

      #define error(args...) (fputs("Error: ",stdout),printf(args),puts(""))
      

      C99 用户也可以说:

      #define error(...) (fputs("Error: ",stdout),printf(__VA_ARGS__),puts(""))
      

      但有some problems 使用__VA_ARGS__。幸运的是,有一个 GCC 扩展来处理它,但随后您又回到了使用特定于编译器的扩展,并且args... 模式更广泛可用。

      【讨论】:

        【解决方案5】:

        许多编译器都支持 GNU 风格的可变参数宏,如下所示:

        #define error(format,args...) do { \
          fprintf(stderr, "error: " format "\n", ##args); \
          abort(); \
        } while(0)
        

        但是,如果您的目标是可移植性,请不要使用可变参数宏。

        【讨论】:

        • @Laalto:谢谢。我在 MSVC6.0、MSVS-2005 编译器中尝试过,它似乎不支持可变参数宏。我猜 GCC 支持,但是你知道任何基于 Windows 的编译器支持这个吗?
        • 我已经在 Metrowerks CodeWarrior 和 Windows 上的各种 GCC 上使用了这个结构。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多