如何将变量参数函数转换为宏?

时间:2009-08-25 12:05:24

标签: c function macros variadic-functions

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

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()}

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

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

修复是什么?

5 个答案:

答案 0 :(得分:2)

如果编译器支持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。如果您希望定义驻留在头文件中,那么可能是静态内联函数?

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
}

答案 1 :(得分:1)

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

您使用的是哪种编译器?

答案 2 :(得分:0)

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

为什么要用宏替换功能(根据你这样工作正常)?

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

有一个共同的扩展可以做你想要的,只需写:

#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...模式可以更广泛地使用。