Avoiding name collisions in macros

P

Peter Ammon

Let's say I need to swap two int values frequently. I would write a macro:

#define swap(int a, int b) \
do { \
int temp = (a); \
(a) = (b); \
(b) = temp; \
} while (0)


Aside from the double evaluation of a and b, this works fine *except*
when either macro parameter a or b is called "temp." What's the best to
design macros to avoid these sort of collisions?

Is this a good candiate for using an identifier from that murky
legal-only-as-a-local-variable set, like _temp?

Thanks for your thoughts,
-Peter

(PS Yes, I know about various tricks with bitwise XOR, but I'm
interested in a general solution)
 
E

Emmanuel Delahaye

In 'comp.lang.c' said:
Let's say I need to swap two int values frequently. I would write a macro:

#define swap(int a, int b) \

Macro parameters have no type (or you mean 'inline').
Please don't retype, but copy and paste.

#define swap(a, b) \
do { \
int temp = (a); \

Hence, the macro name should be 'swap_int', or 'swap_i' or the like...
(a) = (b); \
(b) = temp; \
} while (0)

Aside from the double evaluation of a and b, this works fine *except*
when either macro parameter a or b is called "temp." What's the best to
design macros to avoid these sort of collisions?

Is this a good candiate for using an identifier from that murky
legal-only-as-a-local-variable set, like _temp?

I'm not sure it's legal, hence I prefer to postfix with '_'

#define swap(a_, b_) \
do { \
int temp_ = (a_); \
etc.

A little ugly, I concede...
 
E

Ed Morton

Hence, the macro name should be 'swap_int', or 'swap_i' or the like...

If you're going to do that it's presumably because you have different
types you need to swap so you could just pass in the type as an argument
to one macro instead of creating several similair macros, e.g.:

#define swap(type,a,b) \
do { \
type _temp; \
...
Yes.


I'm not sure it's legal, hence I prefer to postfix with '_'

#define swap(a_, b_) \
do { \
int temp_ = (a_); \
etc.

A little ugly, I concede...

No need for the underscores on the parameters.

Ed.
 
P

Peter Ammon

Emmanuel said:
Macro parameters have no type (or you mean 'inline').

Oops :)
Please don't retype, but copy and paste.

The code isn't actually C, but the general problem is. But since you
asked...

#define ASSIGN(a, b) do { id _temp = (a); (a)=[(b) retain]; [_temp
release]; } while (0)

#define ASSIGN_COPY(a, b) do { id _temp = (a); (a) = [(b) copy]; [_temp
release]; } while (0)
 
P

Peter Shaggy Haywood

Groovy hepcat Peter Ammon was jivin' on Fri, 21 May 2004 11:54:41
-0700 in comp.lang.c.
Avoiding name collisions in macros's a cool scene! Dig it!
Let's say I need to swap two int values frequently. I would write a macro:

#define swap(int a, int b) \
do { \
int temp = (a); \
(a) = (b); \
(b) = temp; \
} while (0)

Aside from the double evaluation of a and b, this works fine *except*
when either macro parameter a or b is called "temp." What's the best to
design macros to avoid these sort of collisions?

Try creating some kind of Frankenstein's monster thingie with token
concatenation, maybe. Concatenate the names of the two macro arguments
together (and append or prepend temp or something to avoid the
resulting token being a keyword or something) and use the resulting
token as the variable's identifier. For example:

#include <stdio.h>

#define PASTE_(a, b) a ## b
#define PASTE(a, b) PASTE_(a, b)
#define SWAP(t, a, b) do{t PASTE(PASTE(a, b), temp) = (a); \
(a) = (b); \
(b) = PASTE(PASTE(a, b), temp);}while(0)

int main(void)
{
int x = 1, y = 9;

printf("x = %d, y = %d\n", x, y);
SWAP(int, x, y);
printf("x = %d, y = %d\n", x, y);

return 0;
}

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 
M

Martin Dickopp

Groovy hepcat Peter Ammon was jivin' on Fri, 21 May 2004 11:54:41
-0700 in comp.lang.c.
Avoiding name collisions in macros's a cool scene! Dig it!


Try creating some kind of Frankenstein's monster thingie with token
concatenation, maybe. Concatenate the names of the two macro arguments
together (and append or prepend temp or something to avoid the
resulting token being a keyword or something) and use the resulting
token as the variable's identifier. For example:

#include <stdio.h>

#define PASTE_(a, b) a ## b
#define PASTE(a, b) PASTE_(a, b)
#define SWAP(t, a, b) do{t PASTE(PASTE(a, b), temp) = (a); \
(a) = (b); \
(b) = PASTE(PASTE(a, b), temp);}while(0)

int main(void)
{
int x = 1, y = 9;

printf("x = %d, y = %d\n", x, y);
SWAP(int, x, y);
printf("x = %d, y = %d\n", x, y);

return 0;
}

This technique only works if the second and third macro arguments are
identifiers. Otherwise, the pasting doesn't yield a valid preprocessor
token, e.g.

int a [] = {1, 9};
SWAP (int, a [0], a [1]);

doesn't work.

It also "pollutes" the namespace with `PASTE' and `PASTE_'. If that is
acceptable, why not go for the following much simpler solution:

#define SWAP(t, a, b) do { t PASTE = (a); \
(a) = (b); \
(b) = PASTE; } while (0)

Martin
 
C

Chris Torek

[The token-pasting] technique [using the names of the variables
to be swapped] only works if the second and third macro arguments are
identifiers. Otherwise, the pasting doesn't yield a valid preprocessor
token, e.g.

int a [] = {1, 9};
SWAP (int, a [0], a [1]);

doesn't work.
Indeed.

It also "pollutes" the namespace with `PASTE' and `PASTE_'. If that is
acceptable, why not go for the following much simpler solution:

#define SWAP(t, a, b) do { t PASTE = (a); \
(a) = (b); \
(b) = PASTE; } while (0)

My usual method is just to write such swaps in-line, e.g., when
expanding a specialized sort function in C (in C++ one would just
use templates; and in Ada one would use generics, and so on; in
these languages the problem has a "language-preferred" solution).
If for some reason a swap macro appeals, one could perhaps do away
with the "type" parameter entirely, and supply instead a "temporary
variable" parameter:

#define SWAP(t, a, b) (t = (a), (a) = (b), (b) = t)
...
int a[N];
int swaptmp;
...
SWAP(swaptmp, a, a[j]); /* cf. SWAP(int, a, a[j]) */

In this version of the macro, I deliberately did not parenthesize
occurrences of the name "t" because it is supposed to be a simple
variable of the appropriate type.

If one wishes to reduce the scope of the variable to just the braces
introduced by a do-while(0) (e.g., to assist a compiler in
optimization) there is another variant of this method:

#define SWAP(t, v, a, b) \
do { t v = (a); (a) = (b); (b) = v; } while (0)
...
SWAP(int, swaptmp, a, a[j]);

So far, however, it has been my experience that compilers smart
enough to optimize swaps into machine-level XCHG instructions (or
equivalent) are also smart enough to do dataflow and lifetime
analysis on variables, so that they can already determine that
the "swaptmp" variable's value persists only for the one source
line.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top