Variadic macros for debug purposes

Started by
7 comments, last by koralcem 15 years, 12 months ago
Hi guys, I was trying to write a variadic macro to be able to check some values as my game is running and I came across the following problem: I want a macro that will check an expression and, if it's false, print the expression that failed along with other info into a text file. I also wanted to allow for printing a custom message, if given. So I have an ASSERT(x, ...) macro which has the following line after all the info printing is done (where err_log is a proper FILE*): fprintf(err_log, "Msg: "__VA_ARGS__); This works as intended when the user does give it a message, but if he doesn't I get "C2660: 'fprintf': function does not take 1 arguments". Shouldn't __VA_ARGS__ amount to nothing if no other parameters are passed? So shouldn't I end up with printing just "Msg: " to the file? I would greatly appreciate it if someone could point out what I'm missing here. Another thing that might help me out: Is there a way, from within the macro, to check whether __VA_ARGS__ will expand to anything at all (i.e. if it's "empty")? If so, maybe I can just put an if/else in there to print nothing if a message wasn't given. A preemptive thanks,
Cem SchemelDigiPen, RTIS
Advertisement
Try wrapping the fprintf in your own function that takes nothing but a variable argument list (and internally prepends the "Msg: " string). This should help you reduce dependencies and hide data too.
The following
#include <cstdio>#define TEST(x,...) if((x)) { fprintf(stdout,"Msg: " __VA_ARGS__); }int main() {    TEST(true);    TEST(true,"PRINT\n");}

produces the expected results for me with VS2008. What's your actual code look like? The error is interesting -- it says you're trying to call fprintf() with one parameter. But you should have at least two, according do your examples. I think the problem lies in part of the code you have not shown us.
Excellent point Josh,

Below is the file which will house the macros (hope formatting doesn't blow up):

//-----------------------------------------------------------------------
#ifndef DEBUG_TOOLS_H
#define DEBUG_TOOLS_H
//-----------------------------------------------------------------------

//files needed in the debug macros
#include <stdio.h> //printf(), fprintf()

//-----------------------------------------------------------------------

#ifdef DEBUG_MODE

#define ASSERT(x,...)
{
if(0 == (x))
{
FILE* err_log;
err_log = fopen("error_log.txt", "wt");
printf("assert!\n");
fprintf(err_log, "Failed expression: %s\nIn function: %s\nLine: %d\nIn file: %s\n", #x, __FUNCTION__, __LINE__, __FILE__);
printf(err_log, "\n");
fprintf(err_log, "Msg: "__VA_ARGS__);
fclose(err_log);
}
}
#else //#ifdef DEBUG_MODE. if DEBUG_MODE isn't defined the macros don't do anything
#define ASSERT(x)
#endif //#ifdef DEBUG_MODE

//------------------------------------------------------------------------
#endif //DEBUG_TOOLS_H

And my main is simply:

#include "debug_tools.h"

int main(void)
{
int y = 0;
ASSERT(y);
return 0;
}

which produces the following:

error C2143: syntax error : missing ')' before 'string', main.cpp, 6
error C2660: 'fprintf' : function does not take 1 arguments, main.cpp, 6
error C2059: syntax error : ')', main.cpp, Line:6

I am using Visual Studio 2005. Would that make a difference in the way macros are handled?
Cem SchemelDigiPen, RTIS
Can you do this:

#define ASSERT(x,...)
{
if(0 == (x))

or shouldn't you have the \ line terminators for a multiline define?
Sorry to have left those out. I do have them in the actual file but apparently I deleted them while trying to make the formatting work in html, and forgot to put them back in.

Edit: Josh, I tried copy/pasting your code exactly into my program and it still complains about calling fprintf with one argument. Could the problem be the compiler?


[Edited by - koralcem on April 22, 2008 11:09:35 PM]
Cem SchemelDigiPen, RTIS
What compiler are you using? Its only relatively recently that these have compiled across the different platforms I use at work (VS was a relatively early adopter I think).

Does this compile as expected for you?:

static inline void Foo(...){}
#define ASSERT(x,...) do { Foo(__VA_ARGS__); } while(0)

//Tests (Compile in VS'08)
ASSERT(0, "bob");
ASSERT(0, "bob %s", "and sheila");
ASSERT(0);
Quote:
Edit: Josh, I tried copy/pasting your code exactly into my program and it still complains about calling fprintf with one argument. Could the problem be the compiler?

It may be. Your example worked when I copied it. 2005 may have different semantics for the operation of that macro expansion -- could be what's causing it to swallow one of the parameters.
Yeah, I'm assuming it's just the compiler then. I'll just make 2 different macros, one for when the user wants to supply a message and one when not. Thanks a lot though, I really appreciate your guys' time.
Cem SchemelDigiPen, RTIS

This topic is closed to new replies.

Advertisement