I know how to swap 2 variables in c++ , ie you use std::swap(a,b)
.
question:
Does the C
standard library have a similar function
This works quickly in Clang and gcc (but not icc, which doesn't recognize this swap function - however, it will compile in any standard C99 compiler), provided that the optimizations actually recognize the swap (they do on high enough optimization levels).
#include <string.h>
#define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b)))
static inline void swap_internal(void *a, void *b, size_t size) {
char tmp[size];
memcpy(tmp, a, size);
memmove(a, b, size);
memcpy(b, tmp, size);
}
Now for explaining how it works. First, the SWAP()
line is relatively strange, but it's actually relatively simple. &(a)
is argument a
passed as a pointer. Similarly, &(b)
is argument b
passed as an pointer.
The most interesting piece of code is sizeof *(1 ? &(a) : &(b))
. This is actually a relatively clever piece of error reporting. If error reporting wouldn't be needed, it could be just sizeof(a)
. Ternary operator requires that its operations have compatible types. In this case, I check two different arguments for their type compatibility by converting them to pointer (otherwise, int
and double
would be compatible). As int *
and double *
aren't compatible, compilation would fail... provided it's standard C compiler. Sadly, many compilers assume void *
type in this case, so it fails, but at least with a warning (that is enabled by default). To ensure correct size of the result, the value is dereferenced, and applied to sizeof
, so there are no sideeffects.
~/c/swap $ gcc swap.c
swap.c: In function ‘main’:
swap.c:5:64: warning: pointer type mismatch in conditional expression [enabled by default]
#define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b)))
^
swap.c:16:5: note: in expansion of macro ‘SWAP’
SWAP(cat, dog);
^
~/c/swap $ clang swap.c
swap.c:16:5: warning: pointer type mismatch ('int *' and 'double *') [-Wpointer-type-mismatch]
SWAP(cat, dog);
^~~~~~~~~~~~~~
swap.c:5:57: note: expanded from macro 'SWAP'
#define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b)))
^ ~~~~ ~~~~
1 warning generated.
~/c/swap $ icc swap.c
swap.c(16): warning #42: operand types are incompatible ("int *" and "double *")
SWAP(cat, dog);
^
This macro evaluates everything exactly once (sizeof
is special, as it doesn't evaluate its arguments). This provides safety against arguments like array[something()]
. The only limitation I can think of is that it doesn't work on register
variables because it depends on pointers, but other than that, it's generic - you can even use it for variable length arrays. It can even handle swapping identical variables - not that you would want to do that.
There is no equivalent in C - in fact there can't be, as C doesn't have template functions. You will have to write separate functions for all the types you want to swap.
Check your compiler documentation. The compiler may have a swapb
function for swapping bytes and my provide other similar functions.
Worst case, waste a day and write some generic swap functions. It won't consume a significant amount of your project's schedule.
In case of numeric values (at least):
I know this is not an actual or complete answer but until now everyone has been making use of temporary variables so I thought Chris Taylors blog might be relevant to mention, it certainly does remove the need for typeof() etc.
a = a ^ b;
b = a ^ b;
a = a ^ b;
or
a = a + b;
b = a - b;
a = a - b;
In theory I suppose these techniques could be applied to strings and other types as well..
Still only three operations.