2010-03-22

#1 C Macro Pet Peeve: use do while 0

I cannot fathom why I still see compound macros like:
#define TRACE(fmt, ...) { \
printf(fmt, ##__VA_ARGS__); fflush(stdout); \
}

Please, use do while 0:
#define TRACE(fmt, ...) do { \
printf(fmt, ##__VA_ARGS__); fflush(stdout); \
} while (0)

Don't worry. Your (any remotely recent) compiler will not generate any assembly code for the "do while 0". For an explanation, just search do while 0. The basic idea is that you want these kind of macros to behave like normal C void methods. However, if you use the original macro in an expression such as "if (expr) TRACE("yes"); else TRACE("no");", the semicolons after the expansion will cause syntax errors.

For more options to use instead of do while 0, see G_STMT_START/END macros in glib.h, depending on what your compiler allows:
#define TRACE(fmt, ...) if(0) { \
printf(fmt, ##__VA_ARGS__); fflush(stdout); \
} else (void)0

#define TRACE(fmt, ...) (void) ({ \
printf(fmt, ##__VA_ARGS__); fflush(stdout); \
})

C Macro School

C is language I use most commonly. One of the least developed features of C (and coincidentally my favorite feature) is its macro preprocessor. Luckily, during the past decade GCC has implemented many improvements that ease the creation of very powerful macros.

Over the course of my projects, I very often work with someone else or on someone else's code, and I am surprised that even after 15 years, I keep seeing the same mistakes. So I am going to list my list of "My 10 Greatest Pet Peeves with C Macros". Well there may not be 10, but there are many. So let's begin...

Hello

Hi, welcome to my new blog on all things software. I am a software engineer. My friends tease me that I only attended an Institute. I am here to assert myself. Keep on reading...