views:

402

answers:

5

Hello,

I have a variable argument function which prints error messages in my application,whose code is given below.

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

This function error()is used in error conditions as follows:

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

Function error() is called from Different places with different arguments(Variable argument function).

Function approach works fine.

Now if i have to make this function error() as a macro, how do i do it. I tried doing as:

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

But this does not print the arguments correctly.

What is wrong in the macro definition above.

What is the fix?

Thank you.

-AD

A: 

Macros do not (yet?) support variadic arguments and anyway, using va_list wouldn't work here, it only works on variadic function arguments.

Why do you want to replace the function (which works fine, according to you) with a macro anyway?

Konrad Rudolph
+1  A: 

Here is an article with some examples on variable arguments used in a macro. It looks like it should do what you're looking for. You can use __VA_ARGS__ in your macro.

Which compiler are you using?

Kieveli
It looks like it would work all right. but WHY replace a perfectly good function call with a macro? It's not like in-lining the code is going to make any difference to performance or anything in this case. It's just taking some decent code and turning it into crap code
Glen
A: 

Many compilers support GNU style variadic macros, like this:

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

However, if you aim for portability, do not use variadic macros.

laalto
@Laalto: Thanks. I tried it in MSVC6.0, MSVS-2005 compilers, it doesnot seem to support variable argument macros. I guess GCC supports, but do u know of any windows based compiler supporting this?
goldenmean
I've used this construct on Metrowerks CodeWarrior and various flavors of GCC on Windows.
laalto
+1  A: 

If you compiler supports ISO style variadic macros, you can define a macro as such

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

Alternatively, if you are using GCC, there's also the GNU style variadic macros used as such:

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

For more information, see http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

Update

If your compiler does not have variadic macros support, a (poor?) alternative would be to stick to the va_list in function approach. If you wish the definition to reside in a header file, then perhaps a static inline 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
}
lsc
@shawnchin: Thanks. I tried it in MSVC6.0, MSVS-2005 compilers, it doesnot seem to support variable argument macros. I guess GCC supports, but do u know of any windows based compiler supporting this?
goldenmean
@goldenmean: This site says that ISO style Variadic macros was introduced in MSVS-2005 Visual C++ (http://msdn.microsoft.com/en-us/library/ms177415(VS.80).aspx)
lsc
@shawnchin: Are there any peculiar MSVisual Studio project options which one needs to set to enable the compiler to compile this variadic macros. I tried setting few options(e.g. Compile code as C++) Is there any macro to force the compiler to accept these variadic macro extensions(Are they C99 extensions)?
goldenmean
While i was going through other SO posts, i can across this link: http://stackoverflow.com/questions/139479/how-universally-is-c99-supported/139506#139506/ which says MSVS2005 might not have support for C99 features(Varuiadic macros being one of C99 feature).
goldenmean
I'm afraid I don't have an MSVS installation to test it out. However, google search results and this SO post (http://stackoverflow.com/questions/65037/is-there-a-way-to-write-macros-with-a-variable-argument-list-in-visual-c/65103#65103) claim that variadic macros are indeed supported from VC++ 2005 onwards.
lsc
A: 

There's a common extension that does what you want, simply write:

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

C99 users can also say:

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

but there are some problems with using __VA_ARGS__. Fortunately there's a GCC extension to deal with it, but then you're back to using a compiler-specific extension, and the args... mode is more widely available.

geocar