[comp.lang.c] Swapping two variables in place

awm@shamash.cdc.com (Allan Magnuson) (09/22/90)

There was a message a while back about not being able to create a good
#define function to swap two variables.

How about this one: #define swap(a,b) a^=b^=a^=b

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/22/90)

In article <26101@shamash.cdc.com> awm@shamash.UUCP (Allan Magnuson) writes:
> There was a message a while back about not being able to create a good
> #define function to swap two variables.
> How about this one: #define swap(a,b) a^=b^=a^=b

Is this in the FAQ list? That swap is slow, ugly, and won't work for
pointers or floats on any machine.

The best truly portable inline replacement for void swap(a,b) float *a;
float *b; { float t = *a; *a = *b; *b = t; } is

  #define swap(a,b) do { float *swap_a = a; float *swap_b = b; float \
  swap_t = *swap_a; *swap_a = *swap_b; *swap_b = swap_t; } while(0)

which will fail only if any swap_* is defined as a macro. You can, of
course, generalize this into swap(a,b,type).

If you have a swap that is unsafe or uses its arguments by reference,
please obey convention and give it an upper-only name like SWAP.

---Dan

horne-scott@cs.yale.edu (Scott Horne) (09/23/90)

In article <26101@shamash.cdc.com> awm@shamash.UUCP (Allan Magnuson) writes:
>There was a message a while back about not being able to create a good
>#define function to swap two variables.
>
>How about this one: #define swap(a,b) a^=b^=a^=b

I prefer

#define ___(_,__)(_^=__^=_^=__)

It's delightfully difficult to read, isn't it?  :-)  "Oh, that?  It swaps
variables.  Can't you tell?"  :-)

But it won't work on `float's and `double's, as `^' is defined only on
integral types.

					--Scott

-- 
Scott Horne                               ...!{harvard,cmcl2,decvax}!yale!horne
horne@cs.Yale.edu      SnailMail:  Box 7196 Yale Station, New Haven, CT   06520
203 436-1817                    Residence:  Rm 1817 Silliman College, Yale Univ
Uneasy lies the head that wears the _gao1 mao4zi_.

tac@cs.brown.edu (Theodore A. Camus) (09/24/90)

>There was a message a while back about not being able to create a good
>#define function to swap two variables.
>
>How about this one: #define swap(a,b) a^=b^=a^=b

>But it won't work on `float's and `double's, as `^' is defined only on
>integral types.


Nor would it work for swap(i,A[i]).  
In fact, the usual { tmp = i ;  i = A[i] ; A[i] = tmp }  
would fail too.  Thus the danger of call-by-name.  

[ref 2nd Dragon book]



  CSnet:     tac@cs.brown.edu                          Ted Camus  
  ARPAnet:   tac%cs.brown.edu@relay.cs.net             Box 1910 CS Dept
  BITnet:    tac@browncs.BITNET                        Brown University
  "An ounce of example is worth a pound of theory."    Providence, RI 02912

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/24/90)

In article <26101@shamash.cdc.com>, awm@shamash.cdc.com (Allan Magnuson) writes:
> There was a message a while back about not being able to create a good
> #define function to swap two variables.
> 
> How about this one: #define swap(a,b) a^=b^=a^=b

Hmm, let's see:
	double x, y;	swap(x, y);	Drat!
Try again:
	char *x, *y;	swap(x, y);	Drat!
Easy one:
	int i;		swap(i, i);	Drat! (i becomes 0)

Using a GCC extension, we can do

#define swap(x,y) do {typeof(x) ZZT = (x); (x) = (y); (y) = ZZT;} while (0)

which works in a lot of cases, but has problems of its own.
For example, swap(*p++, *--q);

For the record, the version using assignments is often *faster* than
the XOR-based version, as well as being more generally applicable.
-- 
Heuer's Law:  Any feature is a bug unless it can be turned off.