The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 4.14 on page 91
Define a macro swap(t,x,y) that interchanges two arguments of type t . (Block structure will help.)
Solutions by Gregory Pietsch and Lars Wirzenius
Here are Greg's solutions for Cat 0 and Cat 1:
/* EXERCISE 4-14 Gregory Pietsch */ /* conditional compilation added by RJH */ #ifdef CATEGORY_0 #define swap(t,x,y) do{t z=x;x=y;y=z}while(0) #else #ifdef CATEGORY_1 /* This works if I can use the assignment operator on type t. I didn't know if I was allowed to use sizeof or not and still remain Level 0, otherwise this one is better: */ #define swap(t,x,y) do { (unsigned char *)a=(unsigned char *)(&(x)); (unsigned char *)b=(unsigned char *)(&(y)); size_t i = sizeof(t); while (i--) { *\ a ^= *b; *\ b ^= *a; *\ a ^= *b; a\ ++; b\ ++; } \ } while (\ 0) #endif #endif /* editor's note: sizeof is first mentioned on p91, after this exercise, * and is not explained properly until p135, so it can be used in * [[K&R2 solutions:Ancillary:Category numbers|Category 0]] solutions only for exercises 6-1 onward. */
...and here is a lively entry for Category 0, from Lars, which uses token pasting
to derive a name for the temporary variable:
/* * Solution to exercise 4-14 in K&R2, page 91: * * Define a macro swap(t,x,y) that interchanges two arguments of type t. * (Block structure will help.) * * Feel free to modify and copy, if you really must, but preferably not. * This is just an exercise in preprocessor mechanics, not an example of * how it should really be used. The trickery is not worth it to save three * lines of code. * * To exchange the values of two variables we need a temporary variable and * this one needs a name. Any name we pick, the user of the macro might also * use. Thus, we use the preprocessor argument concatenation operator ## to * create the name from the actual variable names in the call. This guarantees * that the result won't be either of the actual arguments. In order to * make sure the result also does not fall into the implementation's name * space, we prefix the name with something safe. * * Lars Wirzenius <liw@iki.fi> */ #include <stdio.h> #define swap(t, x, y) do { t safe ## x ## y; safe ## x ## y = x; x = y; y = safe ## x ## y; } while (0) int main(void) { int ix, iy; double dx, dy; char *px, *py; ix = 42; iy = 69; printf("integers before swap: %d and %d\n", ix, iy); swap(int, ix, iy); printf("integers after swap: %d and %d\n", ix, iy); dx = 123.0; dy = 321.0; printf("doubles before swap: %g and %g\n", dx, dy); swap(double, dx, dy); printf("integers after swap: %g and %g\n", dx, dy); px = "hello"; py = "world"; printf("pointers before swap: %s and %s\n", px, py); swap(char *, px, py); printf("integers after swap: %s and %s\n", px, py); return 0; }
...and here is yet another solution from Gregory:
#define swap(t,x,y) \ do { \ (unsigned char *)_0=(unsigned char *)(&(x)); \ (unsigned char *)_1=(unsigned char *)(&(y)); \ unsigned long _2 = (unsigned long) \ ((unsigned char *)(&(x)+1) \ - (unsigned char *)(&(x))); \ while (_2--) { \ *_0 ^= *_1; \ *_1 ^= *_0; \ *_0 ^= *_1; \ _0++; \ _1++; \ } \ } while (0)










