ANSI C equivalent of try/catch? - c++
I have some C code I'm working with, and I'm finding errors when the code is running but have little info about how to do a proper try/catch (as in C# or C++).
For instance in C++ I'd just do:
try{
//some stuff
}
catch(...)
{
//handle error
}
but in ANSI C I'm a bit lost. I tried some online searches but I don't see enough info about how to make it happen / figured I'd ask here in case anyone can point me in the right direction.
Here's the code I'm working with (fairly simple, recursive method) and would like to wrap with try/catch (or equivalent error-handling structure).
However my main question is simply how to do a try / catch in ANSI C...the implementation / example doesn't have to be recursive.
void getInfo( int offset, myfile::MyItem * item )
{
ll::String myOtherInfo = item->getOtherInfo();
if( myOtherInfo.isNull() )
myOtherInfo = "";
ll::String getOne = "";
myfile::Abc * abc = item->getOrig();
if( abc != NULL )
{
getOne = abc->getOne();
}
for( int i = 0 ; i < offset ; i++ )
{
printf("found: %d", i);
}
if( abc != NULL )
abc->release();
int childCount = item->getChildCount();
offset++;
for( int i = 0 ; i < childCount ; i++ )
getInfo( offset, item->getChild(i) );
item->release();
}
Generally, you don't.
It's possible to use setjmp and longjmp to build something fairly similar to try/catch, although there's no such thing in C as destructors or stack unwinding, so RAII is out of the question. You could even approximate RAII with a so-called "cleanup stack" (see for example Symbian/C++), although it's not a very close approximation, and it's a lot of work.
The usual way to indicate errors or failure in C is to return a value indicating success status. Callers examine the return value and act accordingly. See for example the standard C functions: printf, read, open, for ideas how to specify your functions.
When mixing C and C++ code, you must ensure that a C++ exception never reaches C code. When writing C++ functions that will be called from C, catch everything.
C does not support exception handling.
There is info on one approach to this problem here. This shows the simple setjmp/longjmp approach but also provides a more sophisticated alternative, covered in depth.
There is the classic unwinding gotos pattern:
FILE *if = fopen(...);
FILE *of = NULL;
if (if == NULL) return;
of = fopen(...);
if (of == NULL) goto close_if;
/* ...code... */
if (something_is_wrong) goto close_of;
/* ... other code... */
close_of:
fclose(of);
close_if:
fclose(if);
return state;
Alternately you can fake it in a limited way by isolating the "try" code in another function
int try_code(type *var_we_must_write, othertype var_we_only_read /*, ... */){
/* ...code... */
if (!some_condition) return 1;
/* ...code... */
if (!another_condition) return 2;
/* ...code... */
if (last_way_to_fail) return 4;
return 0;
}
void calling_routine(){
/* ... */
if (try_code(&x,y/*, other state */) ) {
/* do your finally here */
}
/* ... */
}
but neither approach is fully equivalent. You have to manage all the resources yourself, you don't get automatic rollback until a handler is found, and so on...
One useful coding style I like to use is the following. I don't know if it has a particular name but I came across it when I was reverse engineering some assembly code into the equivalent C code. You do lose an indentation level but it's not such a big deal to me. Watch out for reviewer who will point out the infinite loop! :)
int SomeFunction() {
int err = SUCCESS;
do {
err = DoSomethingThatMayFail();
if (err != SUCCESS) {
printf("DoSomethingThatMayFail() failed with %d", err);
break;
}
err = DoSomethingElse();
if (err != SUCCESS) {
printf("DoSomethingElse() failed with %d", err);
break;
}
// ... call as many functions as needed.
// If execution gets there everything succeeded!
return SUCCESS;
while (false);
// Something went wrong!
// Close handles or free memory that may have been allocated successfully.
return err;
}
This is my implementation of an exception handling system in C: exceptions4c.
It's powered by macros, built on top of setjmp and longjmp and it is 100% portable ANSI C.
There you can also find a list of all the different implementations I know of.
You can find a possible implementation with longjmp in this book : C Interfaces and Implementations: Techniques for Creating Reusable Software - David Hanson
And you can find the code here and here as an example of the style used in the book :
except.h
/* $Id$ */
#ifndef EXCEPT_INCLUDED
#define EXCEPT_INCLUDED
#include <setjmp.h>
#define T Except_T
typedef struct T {
const char *reason;
} T;
typedef struct Except_Frame Except_Frame;
struct Except_Frame {
Except_Frame *prev;
jmp_buf env;
const char *file;
int line;
const T *exception;
};
enum { Except_entered=0, Except_raised,
Except_handled, Except_finalized };
extern Except_Frame *Except_stack;
extern const Except_T Assert_Failed;
void Except_raise(const T *e, const char *file,int line);
#ifdef WIN32
#include <windows.h>
extern int Except_index;
extern void Except_init(void);
extern void Except_push(Except_Frame *fp);
extern void Except_pop(void);
#endif
#ifdef WIN32
/* $Id$ */
#define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
#define RERAISE Except_raise(Except_frame.exception, \
Except_frame.file, Except_frame.line)
#define RETURN switch (Except_pop(),0) default: return
#define TRY do { \
volatile int Except_flag; \
Except_Frame Except_frame; \
if (Except_index == -1) \
Except_init(); \
Except_push(&Except_frame); \
Except_flag = setjmp(Except_frame.env); \
if (Except_flag == Except_entered) {
#define EXCEPT(e) \
if (Except_flag == Except_entered) Except_pop(); \
} else if (Except_frame.exception == &(e)) { \
Except_flag = Except_handled;
#define ELSE \
if (Except_flag == Except_entered) Except_pop(); \
} else { \
Except_flag = Except_handled;
#define FINALLY \
if (Except_flag == Except_entered) Except_pop(); \
} { \
if (Except_flag == Except_entered) \
Except_flag = Except_finalized;
#define END_TRY \
if (Except_flag == Except_entered) Except_pop(); \
} if (Except_flag == Except_raised) RERAISE; \
} while (0)
#else
#define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
#define RERAISE Except_raise(Except_frame.exception, \
Except_frame.file, Except_frame.line)
#define RETURN switch (Except_stack = Except_stack->prev,0) default: return
#define TRY do { \
volatile int Except_flag; \
Except_Frame Except_frame; \
Except_frame.prev = Except_stack; \
Except_stack = &Except_frame; \
Except_flag = setjmp(Except_frame.env); \
if (Except_flag == Except_entered) {
#define EXCEPT(e) \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else if (Except_frame.exception == &(e)) { \
Except_flag = Except_handled;
#define ELSE \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else { \
Except_flag = Except_handled;
#define FINALLY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} { \
if (Except_flag == Except_entered) \
Except_flag = Except_finalized;
#define END_TRY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} if (Except_flag == Except_raised) RERAISE; \
} while (0)
#endif
#undef T
#endif
except.c
static char rcsid[] = "$Id$" "\n$Id$";
#include <stdlib.h>
#include <stdio.h>
#include "assert.h"
#include "except.h"
#define T Except_T
Except_Frame *Except_stack = NULL;
void Except_raise(const T *e, const char *file,
int line) {
#ifdef WIN32
Except_Frame *p;
if (Except_index == -1)
Except_init();
p = TlsGetValue(Except_index);
#else
Except_Frame *p = Except_stack;
#endif
assert(e);
if (p == NULL) {
fprintf(stderr, "Uncaught exception");
if (e->reason)
fprintf(stderr, " %s", e->reason);
else
fprintf(stderr, " at 0x%p", e);
if (file && line > 0)
fprintf(stderr, " raised at %s:%d\n", file, line);
fprintf(stderr, "aborting...\n");
fflush(stderr);
abort();
}
p->exception = e;
p->file = file;
p->line = line;
#ifdef WIN32
Except_pop();
#else
Except_stack = Except_stack->prev;
#endif
longjmp(p->env, Except_raised);
}
#ifdef WIN32
_CRTIMP void __cdecl _assert(void *, void *, unsigned);
#undef assert
#define assert(e) ((e) || (_assert(#e, __FILE__, __LINE__), 0))
int Except_index = -1;
void Except_init(void) {
BOOL cond;
Except_index = TlsAlloc();
assert(Except_index != TLS_OUT_OF_INDEXES);
cond = TlsSetValue(Except_index, NULL);
assert(cond == TRUE);
}
void Except_push(Except_Frame *fp) {
BOOL cond;
fp->prev = TlsGetValue(Except_index);
cond = TlsSetValue(Except_index, fp);
assert(cond == TRUE);
}
void Except_pop(void) {
BOOL cond;
Except_Frame *tos = TlsGetValue(Except_index);
cond = TlsSetValue(Except_index, tos->prev);
assert(cond == TRUE);
}
#endif
If you want to do a multiple level jump, look up setjmp() and longjmp(). They can be used as a primitive exception throw. The setjmp() function sets up a return-to place, and returns a status value. The longjmp() function goes to the return-to place, and provides the status value. You can create a catch function by having be called after setjmp() depending on the status value.
Do not, for whatever reason, use them in C++. They do not do stack unwinding or call destructors.
Since C++ was originally implemented as a C pre-processor and it had Try / Catch you could redo Bjarne Stroustrup's work and write a pre-processor to do it.
Related
C++ Unresolved External Symbols Embedded Lua ( based on longjmp issue ) ( not duplicate )
I will describe the problem as follows: Compiler: Visual Studio 2019 The root of the problem is that longjump crashes the process because I manually map my code to the process. The code works fine as follows, but crashes on any syntax error in the lua script due to longjump: extern "C" { #include "lua.h" #include "lualib.h" ..... } I want C++ exceptions originating from: #if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) \ try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ #elif defined(LUA_USE_POSIX) /* }{ */ /* in POSIX, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #else /* }{ */ /* ISO C handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #endif /* } */ Because longjmp crashes my process. So I decided to compile my code with the C++ compiler (without extern C) and: #include "lua.h" #include "lualib.h" ..... This is how I called it. But this also led to the following problem: error LNK2019: unresolved external symbol _lua_pcall ... ... ... I thought a lot about it but couldn't find a solution.It's ridiculous that it's a linker error because all the lua header and c files are joined to my project.
#define LUAI_THROW(L,c) c->throwed = true #define LUAI_TRY(L,c,a) \ __try { a } __except(filter()) { if ((c)->status == 0 && ((c)->throwed)) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ Btw, i solved my throwing exception issue like that. Im not sure its correct or no but not crashing anymore. struct lua_longjmp { struct lua_longjmp *previous; luai_jmpbuf b; volatile int status; /* error code */ bool throwed; }; Works as expected even you build without C++ exceptions
Macro function identifier not found
I created an assert marco that works fine but wanted to make one to break. I copied the assert one and renamed it but not it doesn't work when i use it in one header file but it works everywhere else. I'm getting this error: Severity Code Description Project File Line Suppression State Error C3861 'RADIANT_TEST_BREAK': identifier not found Sandbox F:\Path\Buffer.h 63 Both macros are in the same file, Core.h which is included wherever i need it. #define RADIANT_CORE_ASSERT(x, ...) { if(!(x)) { RADIANT_CORE_ERROR("Assertion Failed: {0}", __VA_ARGS__); __debugbreak(); } } #define RADIANT_TEST_BREAK(x, ...) { if(!(x)) { RADIANT_CORE_ERROR("Assertion Failed: {0}", __VA_ARGS__); __debugbreak(); } } I have no idea why the break one doesn't work in that one place here is the method i am running it from struct BufferElement { std::string Name; ShaderDataType Type; uint32_t Size; uint32_t Offset; bool Normalized; BufferElement(ShaderDataType type, const std::string& name, bool normalized = false) : Name(name), Type(type), Size(ShaderDataTypeSize(type)), Offset(0), Normalized(normalized) { } uint32_t GetComponentCount() const { switch (Type) { case ShaderDataType::Float: return 1; case ShaderDataType::Float2: return 2; } RADIANT_TEST_BREAK(false, "Unknown ShaderDataType!"); return 0; } }; If i swap RADIANT_TEST_BREAK for RADIANT_CORE_ASSERT It works.
I found what was causing the problem. i had the definition in an ifdef but not in the else #ifdef RADIANT_ENABLE_ASSERTS #define RADIANT_CORE_ASSERT(x, ...) { if(!(x)) { RADIANT_CORE_ERROR("Assertion Failed: {0}", __VA_ARGS__); __debugbreak(); } } #define RADIANT_TEST_BREAK(x, ...) { if(!(x)) { RADIANT_CORE_ERROR("Assertion Failed: {0}", __VA_ARGS__); __debugbreak(); } } #else #define RADIANT_CORE_ASSERT(x, ...) //Make sure to include this line #define RADIANT_TEST_BREAK(x, ...) #endif This seems to only be a problem in one place which i still don't know why but this fixed it for me.
C++ assert with time stamp
is that possible to log information when assert failed with time stamp ex. int a = 10 assert( a > 100 ); then it will be failed and output just like with the timestamp as well 2013-12-02 , 17:00:05 assert failed !! (a > 100) line : 22 Thank you
assert is a macro (it has to be one, to give __LINE__ and __FILE__ information). You could define your own. I would name it something else like tassert for readability reasons, perhaps like (untested code) #ifdef NDEBUG #define tassert(Cond) do {if (0 && (Cond)) {}; } while(0) #else #define tassert_at(Cond,Fil,Lin) do { if ((Cond)) { \ time_t now##Lin = time(NULL); \ char tbuf##Lin [64]; struct tm tm##Lin; \ localtime_r(&now##Lin, &tm##Lin); \ strftime (tbuf##Lin, sizeof(tbuf##Lin), \ "%Y-%m-%d,%T", &tm##Lin); \ fprintf(stderr, "tassert %s failure: %s %s:%d\n", \ #Cond, tbuf##Lin, Fil, Lin); \ abort(); }} while(0) #define tassert(Cond) tassert_at(Cond,__FILE__,__LINE__) #endif /*NDEBUG*/ I am using cpp concatenation ## with Lin to lower probability of name collisions, and I am using cpp stringification # to make a string out of Cond macro formal. The Cond is always expanded, to make sure the compiler catch syntactic errors in it even when disabling tassert with NDEBUG as assert(3) does. One could put most of the code in the above macro in some function, e.g. void tassert_at_failure (const char* cond, const char* fil, int lin) { timer_t now = time(NULL); char tbuf[64]; struct tm tm; localtime_r (&now, &tm); strftime (tbuf, sizeof(tbuf), "%Y-%m-%d,%T", &tm); fprintf (stderr, "tassert %s failure: %s %s:%d\n", cond, tbuf, fil, lin); abort(); } and then just define (a bit like <assert.h> does...) #define tassert_at(Cond,Fil,Lin) do { if ((Cond)) { \ tassert_at_failure(#Cond, Fil, Lin); }} while(0) but I don't like much that approach, because for debugging with gdb having abort() being called in the macro is much easier (IMHO size of code for debugging executables does not matter at all; calling abort in a macro is much more convenient inside gdb - making shorter backtraces and avoiding one down command...). If you don't want libc portability and just use recent GNU libc you could simply redefine the Glibc specific __assert_fail function (see inside <assert.h> header file). YMMV. BTW, in real C++ code I prefer to use << for assertion-like debug outputs. This enables usage of my own operator << outputting routines (if you give it as an additional macro argument) so I am thinking of (untested code!) #define tassert_message_at(Cond,Out,Fil,Lin) \ do { if ((Cond)) { \ time_t now##Lin = time(NULL); \ char tbuf##Lin [64]; struct tm tm##Lin; \ localtime_r(&now##Lin, &tm##Lin); \ strftime (tbuf##Lin, sizeof(tbuf##Lin), \ "%Y-%m-%d,%T", &tm##Lin); \ std::clog << "assert " << #Cond << " failed " \ tbuf##Lin << " " << Fil << ":" << Lin \ << Out << std::endl; \ abort (); } } while(0) #define tassert_message(Cond,Out) \ tassert_message_at(Cond,Out,__FILE__,__LINE__) and then I would use tassert_message(i>5,"i=" << i); BTW, you might want to use syslog(3) instead of fprintf in your tassert_at macro.
Mixing C/C++ using macros and C style strings
gcc/g++ 4.7.2 CXXFLAGS -Wall -Wextra -g -O2 Hello, I have this header file (mu_test.h) that is written using C style. It contain the following marcos #define GET_ERROR() ((errno == 0) ? "None" : strerror(errno)) #define LOG_ERR(fmt, ...) fprintf(stderr, "[ERROR] %s:%d: errno: %s " fmt "\n", __func__, __LINE__, GET_ERROR(), ##__VA_ARGS__) #define MU_ASSERT(test, msg) do { \ if(!(test)) { \ LOG_ERR(msg); \ return msg; \ } \ } while(0) I have a cpp file (floor_plan_src.cpp) compiled using g++ that includes the mu_test.h #include "mu_test.h" char* test_memory_allocation() { plan = new floor_plan(); MU_ASSERT(plan != NULL, "Failed to allocate memory for floor_plan"); return NULL; } I get this warning: deprecated conversion from string constant to ‘char*’ So my string constant that I am passing to that function-like marco doesn't like it (C strings) as I have compiled my source using g++. I thought this problem was to do with mixing c/c++. solution 1: wrap all the macros in the mu_test.h with extern "C" #ifdef __cplusplus extern "C" { #endif /* _cplusplus */ #define GET_ERROR() ((errno == 0) ? "None" : strerror(errno)) #define LOG_ERR(fmt, ...) fprintf(stderr, "[ERROR] %s:%d: errno: %s " fmt "\n", __func__, __LINE__, GET_ERROR(), ##__VA_ARGS__) #define MU_ASSERT(test, msg) do { \ if(!(test)) { \ LOG_ERR(msg); \ return msg; \ } \ } while(0) #ifdef __cplusplus } #endif /* __cplusplus */ Solution 1 still gave me the same warning. solution 2: wrap the header file in floor_plan_src.cpp extern "C" { #include "mu_test.h" } Solution 2 still gave me the same warning Solution 3: wrap the function extern "C" char* test_memory_allocation() { plan = new floor_plan(); MU_ASSERT(plan != NULL, "Failed to allocate memory for floor_plan"); return NULL; } Solution 3 same as above Solution 4: Try and convert the constant string to a non-const char* MU_ASSERT(plan != NULL, (char*)"Failed to allocate memory for floor_plan"); gave the following error: expected primary-expression before char "[ERROR] %s:%d: errno: %s " cannot be used as a function Many thanks for any suggestions,
The problem is that your test_memory_allocation might return a string literal, and you shouldn't make a string literal decay to non-const char*: it's allowed in C++, but still deprecated. Your code gets expanded in: char* test_memory_allocation() { plan = new floor_plan(); do { if(!(plan != NULL)) { LOG_ERR("Failed to allocate memory for floor_plan") return "Failed to allocate memory for floor_plan"; } } while(0); return NULL; } To fix it you just need to make test_memory_allocation return a const char* or otherwise you could return a pointer to something that could decay to a non-const char* (for example a static char array or to a heap-allocated memory area). extern "C" is only needed to avoid C++ name mangling, it only affects functions, not macros.
How do you create a debug only function that takes a variable argument list? Like printf()
I'd like to make a debug logging function with the same parameters as printf. But one that can be removed by the pre-processor during optimized builds. For example: Debug_Print("Warning: value %d > 3!\n", value); I've looked at variadic macros but those aren't available on all platforms. gcc supports them, msvc does not.
I still do it the old way, by defining a macro (XTRACE, below) which correlates to either a no-op or a function call with a variable argument list. Internally, call 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 a typical #ifdef switch: #ifdef _DEBUG #define XTRACE XTrace #else #define XTRACE #endif Well that can be cleaned up quite a bit but it's the basic idea.
This is how I do debug print outs in C++. Define 'dout' (debug out) like this: #ifdef DEBUG #define dout cout #else #define dout 0 && cout #endif In the code I use 'dout' just like 'cout'. dout << "in foobar with x= " << x << " and y= " << y << '\n'; If the preprocessor replaces 'dout' with '0 && cout' note that << has higher precedence than && and short-circuit evaluation of && makes the whole line evaluate to 0. Since the 0 is not used the compiler generates no code at all for that line.
Here's something that I do in C/C++. First off, you write a function that uses the varargs stuff (see the link in Stu's posting). Then 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 is to use double-parens when calling the debug function, and the whole line will get removed in non-DEBUG code.
Ah, vsprintf() was the thing I was missing. I can use this to pass the variable argument 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 whole thing in a macro.
Another fun way to stub out variadic functions is: #define function sizeof
#CodingTheWheel: There is one slight problem with your approach. Consider a call such as XTRACE("x=%d", x); This works fine in the debug build, but in the release build it will expand to: ("x=%d", x); Which is perfectly legitimate C and will compile and usually run without side-effects but generates unnecessary code. The approach I usually use to eliminate that problem is: Make the XTrace function return an int (just return 0, the return value doesn't matter) Change the #define in the #else clause to: 0 && XTrace Now the release version will expand to: 0 && XTrace("x=%d", x); and any decent optimizer will throw away the whole thing since short-circuit evaluation would have prevented anything after the && from ever being executed. Of course, just as I wrote that last sentence, I realized that perhaps the original form might be optimized away too and in the case of side effects, such as function calls passed as parameters to XTrace, it might be a better solution since it will make sure that debug and release versions will behave the same.
In C++ you can use the streaming operator 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 then implement customised trace output for classes in much the same way you would do it for outputting to std::cout.
What platforms are they not available on? stdarg is part of the standard library: http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html Any platform not providing it is not a standard C implementation (or very, very old). For those, you will have to use varargs: http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html
Part of the problem with this kind of functionality is that often it requires variadic macros. These were standardized fairly recently(C99), and lots of old C compilers do not support the standard, or have their own special work around. Below is a debug header I wrote that has several 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 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: How to make a variadic macro (variable number of arguments) It should answer your question.
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 nothing at run-time when the _DEBUG_LOG flag is turned off.
This is a TCHAR version of user's answer, so it will work as ASCII (normal), or Unicode mode (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 . But this code will be helpful for debugging purposes , it will print each variable's value along with it's name . This is completely type independent and supports variable number of arguments. And can even display values of STL's nicely , given that you overload 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 : a = string here | b = 7 | c = 3.14
Having come across the problem today, my solution is the following macro: static TCHAR __DEBUG_BUF[1024]; #define DLog(fmt, ...) swprintf(__DEBUG_BUF, fmt, ##__VA_ARGS__); OutputDebugString(__DEBUG_BUF); You can then call the function like this: int value = 42; DLog(L"The answer is: %d\n", value);