Generating unique ids through preprocessors

Some time ago I wanted to optionally include some code via a preprocessor command. Normally this is quite simple. For example, here is a common definition used to handling logged during development.

#ifdef DEBUG
#   define log(tmplt,...) NSLog(tmplt, ##__VA_ARGS__)
#else
#   define log(tmplt,...)
#endif

This is just fine as long as the code being included does not need to create any sort of variable. But what about this piece used for handling weak references in ARC based code:

#define weakRefCallMethod(weakRef, methodCall) \
id aStrongRef = weakRef; \
[aStrongRef methodCall]

At first glance it's just fine. But what if you want to use it twice in the same scope. Now you have a compilation error because aStrongRef is defined twice.
The way to deal with this is to define a macro that can actually mutate the name of a variable to make it unique.

The algorythm I use is to append the current line number of the fine to the variable name. To achieve this we have to employ a number of preprocessor tricks. The first this we need is a set of macros which concatinate two passed pieces of text. We have to employ two macros to do this because of the way macros handle arguments passed to this. The first concatinate macro looks like it does nothing, but in fact it's job is to get the text resolved by the preprocessor before it is handled to the second macro where the concatination is done. Here are the two macros:

#define concatinate(prefix, suffix) _concatinate(prefix, suffix)
#define _concatinate(prefix, suffix) prefix ## suffix

Having this macro available, I can now add a third macro to append lines numbers and then modify my weak reference call macro like this:

#define addLineNumberTo(raw) concatinate(raw, __LINE__)

#define _weakRefCallMethod(strongRef, weakRef, methodCall) \
id strongRef = weakRef; \
[strongRef methodCall]

#define weakRefCallMethod(weakRef, methodCall) \
_weakRefCallMethod(addLineNumberTo(aStrongRef), weakRef, methodCall)

So now lets look at the results. Here is the original code:
Effectively doing this:

12: [aWeakRef methodCall1];
13: [aWeakRef methodCall2:@"abc"];

Here is the code which the macros in place:

12: weakRefCallMethod(aWeakRef methodCall1);
13: weakRefCallMethod(aWeakRef methodCall2:@"abc");

And finally here is what the preprocessor replaces the macros with:

12: id aStrongRef12 = weakRef; 
13: [aStrongRef12 methodCall1];
14: id aStrongRef14 = weakRef; 
15: [aStrongRef14 methodCall2:@"abc"];

Comments powered by Disqus