11

I have some debugging code that looks like the following:

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)
void __my_error(const char*loc, const char *fmt, ...);
#define my_error(fmt, ...) __my_error(AT, fmt, ##__VA_ARGS__)

The last macro is used so I can insert the location into the debug output as to where the error occurred. However, when I call the function like this:

my_error("Uh oh!");

I would like my code to be C99, so I find when this compiles, I get the following error:

error: ISO C99 requires rest arguments to be used

I know I can solve this by changing the call to

my_error("Uh oh!", NULL);

But is there any way to make this look less ugly? Thanks!

Michael Mior
  • 28,107
  • 9
  • 89
  • 113
  • Also you might want to have a look at this answer: http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing (the Single argument section) – David Nov 12 '15 at 10:01
  • 1
    Beware when defining your own names with two adjacent underscores in them: all such names are reserved by the standard (so a library, compiler, or standard update might use them in some way). – mtraceur Nov 16 '21 at 17:31

1 Answers1

15

I see two solutions to this problem. (Three if you count 'stick with gcc').

Extra special case macro

Add a new macro for when you want to print a fixed string.

#define my_errorf(str) my_error(str, NULL)

Pro: Minimum amount of extra code.
Con: It's easy to use the wrong macro (but at least you notice this at compile time).

Put fmt inside the '...'

Vararg macro's can have only __VA_ARGS__ as parameter (unlike vararg functions). So you can put the fmt argument inside the __VA_ARGS__ and change your function.

void __my_error(const char *loc, ...);
#define my_error(...) __my_error(AT, __VA_ARGS__)

Pro: One syntax/macro for all error messages.
Con: Requires rewriting of your __my_error function, which might not be possible.

Michael Mior
  • 28,107
  • 9
  • 89
  • 113
schot
  • 10,958
  • 2
  • 46
  • 71
  • Yes, the two functions are the same (typo on my part). I'll give solution number 2 a try and see if I can sort that out. What do you suggest for naming conventions for things which are essentially private (such as the `__my_error` function, which should never be called directly)? – Michael Mior Aug 31 '10 at 11:59
  • @Michael Let me know how it works out. I usually add a '_suffix' to the macro name like `my_error_real`, `my_error_private` or just `my_error_x` (from 'eXpanded'). – schot Aug 31 '10 at 12:19
  • 2
    Vararg macros *can* have more than just __VA_ARGS__ as a parameter. You could, for example, pass a FILE* (for fprintf) or a char[] (for snprintf). It's just that the ... must match at least one argument, at least in gcc's interpretation of C99. – Martin Dorey Nov 23 '12 at 02:25
  • Those are workarounds, not a way to disable the warning :( – Tomáš Zato Nov 26 '16 at 23:08
  • 1
    Putting `fmt` inside `...` will prevent you from prepending and appending to the format string. – jg6 Dec 10 '20 at 21:35
  • Why does the second option requre rewriting the function? The macro expansion is just textual, it doesn't care if the first argument from `__VA_ARGS__` lines up with the first `...` of the function, right? So is there some other reason I'm missing? – mtraceur Nov 16 '21 at 18:28