The only trouble you might get with this, is some smart-a$$ code analyzer screaming about a 'constant expression in do-while condition'. That's usually easy to turn off by adding some comment-directive to your macro definition. Just make sure you only use /*C-style comments*/ in macros ;-)
#define MYMACRO(a,b,c) \
do { \
a = b + c; \
b = c*2; \
} while (0)
What are the remaining troubles with it? What about the following invocation: MYMACRO(x,y,x+y)
As you can probably see the b = c*2 statement will now expand to y = x+y*2.
Ooops, most likey not what the programmer intended :-)
RULE 2: Always surround macro arguments with parentheses inside the macro body.
#define MYMACRO(a,b,c) \
do { \
(a) = (b) + (c); \
(b) = (c)*2; \
} while (0)
RULE 3: Keep your macros SHORT. Don't write 50-line macros, because when the time comes to chase down some bug you will soon find out that the only debugger that could step into macro definitions (SoftICE) is out of business. To the best of my knowledge, even WinDBG, the Windows kernel debugger, cannot step into macros. So, keep'em short.
RULE 4: Be very careful when trying to use macros for speed optimizations (i.e. save a function call). I have seen even senior programmers get it wrong, because they didn't realize that passing MyArray[x+3] as a macro argument would lexically copy this expression in multiple locations in the macro expansion, causing the generated code to needlessly evaluate *(Myarray+x+3) again and again and again. Always have someone else, preferably more experienced than yourself, check these 'optimizations' with you.
I will sum up with a super hot macro tip, that doesn't have to do with avoiding mistakes, but with a thing I needed a billion times but thought was not possible, only to find out about a year ago that it is absolutely doable: Macros with a variable number of arguments, officially called variadic macros.
Yes, they are doable and they have at least one important usage:
KdPrint(("Writing debug output macros that don't require %s %s\n,
"double parentheses",
"in each invocation"));
The magic keyword (or whatever it is actually) is: __VA_ARGS__
The sample Win32 code below shows it all in action:
#define DBG_PREFIX "[FrameGrabber] "
#define FGTRACE(_fmt, ...) \
FGDebugPrint(DBG_PREFIX _fmt, __VA_ARGS__)
void FGDebugPrint(char *format, ...)
{
char szMessage[1024];
va_list VaList;
va_start( VaList, format);
vsprintf_s(szMessage, sizeof(szMessage), format, VaList);
OutputDebugString(szMessage);
va_end( VaList );
}
int _tmain(int argc, _TCHAR* argv[])
{
FGTRACE("Hello %d %d\n", argc, 2*argc);
return 0;
}
Note that in the macro definition above, I broke my own rule about parameter parenthesization, but I had to since I count on string token pasting to get my message prefix at the beginning of the debug output message.
Have fun!
Dimitris Staikos
assuming that you are within a C++ enviroment, #define should be banned.
If you just wanna save a function call, why not make it an inline function?
If you just wanna have a constant variable, why not use const and get more info while debugging?
No corner cases please :)
Posted by: thanasisk | December 17, 2008 at 06:00 PM
Kai edw o antilogos :-)
http://lixtetrax.wordpress.com/2008/12/26/refuting-tips-on-writing-c-macros/
Ante, ti 8a ginei, pote 8a grapsoyme ligo C parea? ;)
Posted by: thanasisk | January 02, 2009 at 01:45 PM
http://en.wikipedia.org/wiki/C_preprocessor#Token_concatenation
Posted by: nobody | August 05, 2009 at 02:57 AM
how can you *ever* step into macros? you cannot, macros are processed by preprocessor and the compiler doesnt even know about them. So the generated code (which you effectively debug) doesnt have a hint of macros.
Posted by: foo | August 05, 2009 at 07:55 PM
@foo, the preprocessor could add file/linenumber directives (like the ones it puts when processing #includes), which the compiler can then embed into the object code.
Not saying it would be easy (otherwise all compilers would do it), but it's not impossible in principle.
Posted by: rodrigo | August 07, 2009 at 02:52 AM
The SoftICE debugger could step into macros :-)
Pity it is a dead product...
Posted by: Dimitris Staikos | November 20, 2009 at 01:45 PM