Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write safe and user friendly c/c++ #define macros

I have been thinking about how macros can be written to be safe, readable and intuitive. Proper use of them should be understood by the looks of them and when used incorrectly the compiler should tell you, and not let you introduce an obscure bug.

When writing multiple line define macros I usually find myself constructing them like this to fullfill the desired criteria:

#define macro(x)    do{                      \
                        ... some code line ; \
                        ... some code line ; \
                    }while(0)

This way you can both...

if (a)
{
    macro(a);
}

and...

if (a)
    macro(a);
else
{
    ...
}

A nice feature of this is that if you use them incorrectly you will get a compiler error. This will not compile for example:

if (a)
    macro(a)
else
    b();

However, I have seen SW developers read this kind of macro construct and getting quite perplexed by it. Can you think of alternative ways to write macros that will not deceive the user in a way where they do something other than expected, and still are quite understandable when browsing a new piece of code?

Also, can you find any problems with the do {} while(0) method? It could for example be a situation where you would expect the macro to behave a certain way and where this is not the case.

The reason why i am not completely convinced the do {} while(0) method is good practice is that the macros themselves look a bit weird and take some explaining to anyone (some at least) who has not seen the construct before.

Edit:

Here is an example from one of the links in the comments (thanks!) that i like. It's quite readable I think:

#define MYMACRO(a,b)   \
    if (xyzzy) asdf(); \
    else (void)0

Is it possible to break it?

like image 778
Martin G Avatar asked May 03 '14 12:05

Martin G


1 Answers

A common approach when you want your macro to do nothing, and toggle this behavior with the preprocessor, is to use the void(0) operation.

#if SOMETHINGS
#define macro(x)    do{                      \
                        ... some code line ; \
                        ... some code line ; \
                    }while(0)
#else
#define macro(x) ((void)(0))
#endif

This way you won't break compilation whenever nulling out macro operations

like image 195
Nikos Athanasiou Avatar answered Sep 20 '22 04:09

Nikos Athanasiou