[ACCEPTED]-How do you create a debug only function that takes a variable argument list? Like printf()-c-preprocessor
I still do it the old way, by defining a 7 macro (XTRACE, below) which correlates to 6 either a no-op or a function call with a 5 variable argument list. Internally, call 4 vsnprintf so you can keep the printf syntax:
#include <stdio.h>
void XTrace0(LPCTSTR lpszText)
{
::OutputDebugString(lpszText);
}
void XTrace(LPCTSTR lpszFormat, ...)
{
va_list args;
va_start(args, lpszFormat);
int nBuf;
TCHAR szBuffer[512]; // get rid of this hard-coded buffer
nBuf = _vsnprintf(szBuffer, 511, lpszFormat, args);
::OutputDebugString(szBuffer);
va_end(args);
}
Then 3 a typical #ifdef switch:
#ifdef _DEBUG
#define XTRACE XTrace
#else
#define XTRACE
#endif
Well that can be 2 cleaned up quite a bit but it's the basic 1 idea.
This is how I do debug print outs in C++. Define 8 'dout' (debug out) like this:
#ifdef DEBUG
#define dout cout
#else
#define dout 0 && cout
#endif
In the code 7 I use 'dout' just like 'cout'.
dout << "in foobar with x= " << x << " and y= " << y << '\n';
If the preprocessor 6 replaces 'dout' with '0 && cout' note 5 that << has higher precedence than 4 && and short-circuit evaluation 3 of && makes the whole line evaluate 2 to 0. Since the 0 is not used the compiler 1 generates no code at all for that line.
Here's something that I do in C/C++. First 6 off, you write a function that uses the 5 varargs stuff (see the link in Stu's posting). Then 4 do something like this:
int debug_printf( const char *fmt, ... );
#if defined( DEBUG )
#define DEBUG_PRINTF(x) debug_printf x
#else
#define DEBUG_PRINTF(x)
#endif
DEBUG_PRINTF(( "Format string that takes %s %s\n", "any number", "of args" ));
All you have to remember 3 is to use double-parens when calling the 2 debug function, and the whole line will 1 get removed in non-DEBUG code.
Ah, vsprintf() was the thing I was missing. I 3 can use this to pass the variable argument 2 list directly to printf():
#include <stdarg.h>
#include <stdio.h>
void DBG_PrintImpl(char * format, ...)
{
char buffer[256];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
printf("%s", buffer);
va_end(args);
}
Then wrap the 1 whole thing in a macro.
Another fun way to stub out variadic functions 1 is:
#define function sizeof
@CodingTheWheel:
There is one slight problem 22 with your approach. Consider a call such 21 as
XTRACE("x=%d", x);
This works fine in the debug build, but 20 in the release build it will expand to:
("x=%d", x);
Which 19 is perfectly legitimate C and will compile 18 and usually run without side-effects but 17 generates unnecessary code. The approach 16 I usually use to eliminate that problem 15 is:
Make the XTrace function return an int 14 (just return 0, the return value doesn't 13 matter)
Change the #define in the #else clause 12 to:
0 && XTrace
Now the release version will expand to:
0 && XTrace("x=%d", x);
and 11 any decent optimizer will throw away the 10 whole thing since short-circuit evaluation 9 would have prevented anything after the 8 && from ever being executed.
Of course, just 7 as I wrote that last sentence, I realized 6 that perhaps the original form might be 5 optimized away too and in the case of side 4 effects, such as function calls passed as 3 parameters to XTrace, it might be a better 2 solution since it will make sure that debug 1 and release versions will behave the same.
In C++ you can use the streaming operator 4 to simplify things:
#if defined _DEBUG
class Trace
{
public:
static Trace &GetTrace () { static Trace trace; return trace; }
Trace &operator << (int value) { /* output int */ return *this; }
Trace &operator << (short value) { /* output short */ return *this; }
Trace &operator << (Trace &(*function)(Trace &trace)) { return function (*this); }
static Trace &Endl (Trace &trace) { /* write newline and flush output */ return trace; }
// and so on
};
#define TRACE(message) Trace::GetTrace () << message << Trace::Endl
#else
#define TRACE(message)
#endif
and use it like:
void Function (int param1, short param2)
{
TRACE ("param1 = " << param1 << ", param2 = " << param2);
}
You can 3 then implement customised trace output for 2 classes in much the same way you would do 1 it for outputting to std::cout
.
What platforms are they not available on? stdarg 4 is part of the standard library:
http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html
Any platform 3 not providing it is not a standard C implementation 2 (or very, very old). For those, you will 1 have to use varargs:
http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html
Part of the problem with this kind of functionality 7 is that often it requires variadic macros. These 6 were standardized fairly recently(C99), and 5 lots of old C compilers do not support the 4 standard, or have their own special work around.
Below 3 is a debug header I wrote that has several 2 cool features:
- Supports C99 and C89 syntax for debug macros
- Enable/Disable output based on function argument
- Output to file descriptor(file io)
Note: For some reason I had 1 some slight code formatting problems.
#ifndef _DEBUG_H_
#define _DEBUG_H_
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "stdarg.h"
#include "stdio.h"
#define ENABLE 1
#define DISABLE 0
extern FILE* debug_fd;
int debug_file_init(char *file);
int debug_file_close(void);
#if HAVE_C99
#define PRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stdout, format, ##__VA_ARGS__); \
} \
}
#else
void PRINT(int enable, char *fmt, ...);
#endif
#if _DEBUG
#if HAVE_C99
#define DEBUG(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
}
#define DEBUGPRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, format, ##__VA_ARGS__); \
} \
}
#else /* HAVE_C99 */
void DEBUG(int enable, char *fmt, ...);
void DEBUGPRINT(int enable, char *fmt, ...);
#endif /* HAVE_C99 */
#else /* _DEBUG */
#define DEBUG(x, format, ...)
#define DEBUGPRINT(x, format, ...)
#endif /* _DEBUG */
#endif /* _DEBUG_H_ */
Have a look at this thread:
It should answer 1 your question.
Having come across the problem today, my 2 solution is the following macro:
static TCHAR __DEBUG_BUF[1024];
#define DLog(fmt, ...) swprintf(__DEBUG_BUF, fmt, ##__VA_ARGS__); OutputDebugString(__DEBUG_BUF)
You can 1 then call the function like this:
int value = 42;
DLog(L"The answer is: %d\n", value);
This is what I use:
inline void DPRINTF(int level, char *format, ...)
{
# ifdef _DEBUG_LOG
va_list args;
va_start(args, format);
if(debugPrint & level) {
vfprintf(stdout, format, args);
}
va_end(args);
# endif /* _DEBUG_LOG */
}
which costs absolutely 2 nothing at run-time when the _DEBUG_LOG 1 flag is turned off.
This is a TCHAR version of user's answer, so 2 it will work as ASCII (normal), or Unicode mode 1 (more or less).
#define DEBUG_OUT( fmt, ...) DEBUG_OUT_TCHAR( \
TEXT(##fmt), ##__VA_ARGS__ )
#define DEBUG_OUT_TCHAR( fmt, ...) \
Trace( TEXT("[DEBUG]") #fmt, \
##__VA_ARGS__ )
void Trace(LPCTSTR format, ...)
{
LPTSTR OutputBuf;
OutputBuf = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, \
(size_t)(4096 * sizeof(TCHAR)));
va_list args;
va_start(args, format);
int nBuf;
_vstprintf_s(OutputBuf, 4095, format, args);
::OutputDebugString(OutputBuf);
va_end(args);
LocalFree(OutputBuf); // tyvm @sam shaw
}
I say, "more or less", because it won't automatically convert ASCII string arguments to WCHAR, but it should get you out of most Unicode scrapes without having to worry about wrapping the format string in TEXT() or preceding it with L.
Largely derived from MSDN: Retrieving the Last-Error Code
Not exactly what's asked in the question 8 . But this code will be helpful for debugging 7 purposes , it will print each variable's 6 value along with it's name . This is completely 5 type independent and supports variable number 4 of arguments. And can even display values 3 of STL's nicely , given that you overload 2 output operator for them
#define show(args...) describe(#args,args);
template<typename T>
void describe(string var_name,T value)
{
clog<<var_name<<" = "<<value<<" ";
}
template<typename T,typename... Args>
void describe(string var_names,T value,Args... args)
{
string::size_type pos = var_names.find(',');
string name = var_names.substr(0,pos);
var_names = var_names.substr(pos+1);
clog<<name<<" = "<<value<<" | ";
describe(var_names,args...);
}
Sample Use :
int main()
{
string a;
int b;
double c;
a="string here";
b = 7;
c= 3.14;
show(a,b,c);
}
Output 1 :
a = string here | b = 7 | c = 3.14
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.