Implement generic swap macro in C [duplicate]
Possible Duplicate:
is there an equivalent of std::swap() in c
Hi folks,
I was attempting a problem to write a generic swap macro in C and my macro looks like this:
#define swap(x,y) { x = x + y; y = x - y; x = x - y; }
It works fine for integers and floats but I am unsure if there is any catch in it. What if by generic macro they mean swapping pointers, characters etc ? Can anyone help me with writing a generic macro for swapping every input ?
Thanks
Solution 1:
This works well only with integers.
For floats it will fail (e.g. try running it with a very large float and a very small one).
I would suggest something as follows:
#define swap(x,y) do \
{ unsigned char swap_temp[sizeof(x) == sizeof(y) ? (signed)sizeof(x) : -1]; \
memcpy(swap_temp,&y,sizeof(x)); \
memcpy(&y,&x, sizeof(x)); \
memcpy(&x,swap_temp,sizeof(x)); \
} while(0)
memcpy is pretty optimized when the amount to copy is known at compilation time. Also, there's no need to manually pass a type name or use compiler specific extensions.
Solution 2:
You can do something like this:
#define SWAP(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0)
which you would then invoke like this:
SWAP(a, b, int);
or:
SWAP(x, y, float);
If you are happy to use gcc-specific extensions then you can improve on this like so:
#define SWAP(x, y) do { typeof(x) SWAP = x; x = y; y = SWAP; } while (0)
and then it would just be:
SWAP(a, b);
or:
SWAP(x, y);
This works for most types, including pointers.
Here is a test program:
#include <stdio.h>
#define SWAP(x, y) do { typeof(x) SWAP = x; x = y; y = SWAP; } while (0)
int main(void)
{
int a = 1, b = 2;
float x = 1.0f, y = 2.0f;
int *pa = &a;
int *pb = &b;
printf("BEFORE:\n");
printf("a = %d, b = %d\n", a, b);
printf("x = %f, y = %f\n", x, y);
printf("pa = %p, pb = %p\n", pa, pb);
SWAP(a, b); // swap ints
SWAP(x, y); // swap floats
SWAP(pa, pb); // swap pointers
printf("AFTER:\n");
printf("a = %d, b = %d\n", a, b);
printf("x = %f, y = %f\n", x, y);
printf("pa = %p, pb = %p\n", pa, pb);
return 0;
}