Is there a built-in way to swap two variables in C?
I know how to swap two variables in C++, ie you use std::swap(a,b)
.
Does the C standard library have a similar function to C++'s std::swap()
, or do I have to define it myself?
You need to define it yourself.
-
C doesn't have templates.
-
If such function does exist it would look like
void swap(void* a, void* b, size_t length)
, but unlikestd::swap
, it's not type-safe. -
And there's no hint such function could be inlined, which is important if swapping is frequent (in C99 there's
inline
keyword). -
We could also define a macro like
#define SWAP(a,b,type) {type ttttttttt=a;a=b;b=ttttttttt;}
but it shadows the
ttttttttt
variable, and you need to repeat the type ofa
. (In gcc there'stypeof(a)
to solve this, but you still cannotSWAP(ttttttttt,anything_else);
.) -
And writing a swap in place isn't that difficult either — it's just 3 simple lines of code!
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.
You can do something similar with a macro if you don't mind using a gcc extension to the C language, typeof
:
#include <stdio.h>
#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
int main(void)
{
int a = 4, b = 5;
float x = 4.0f, y = 5.0f;
char *p1 = "Hello";
char *p2 = "World";
SWAP(a, b); // swap two ints, a and b
SWAP(x, y); // swap two floats, x and y
SWAP(p1, p2); // swap two char * pointers, p1 and p2
printf("a = %d, b = %d\n", a, b);
printf("x = %g, y = %g\n", x, y);
printf("p1 = %s, p2 = %s\n", p1, p2);
return 0;
}
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.
In C this is often done using a macro,
there are very simplistic examples, eg:#define SWAP(type,a,b) {type _tmp=a;a=b;b=_tmp;}
... but I wouldn't recommend using them because they have some non-obvious flaws.
This is a macro written to avoid accidental errors.
#define SWAP(type, a_, b_) \
do { \
struct { type *a; type *b; type t; } SWAP; \
SWAP.a = &(a_); \
SWAP.b = &(b_); \
SWAP.t = *SWAP.a; \
*SWAP.a = *SWAP.b; \
*SWAP.b = SWAP.t; \
} while (0)
- Each argument is instantiated only once,
soSWAP(a[i++], b[j++])
doesn't give problem side effects. - temp variable name is also
SWAP
, so as not to cause bugs if a different name happens to collide with the hard-coded name chosen. - It doesn't call
memcpy
(which in fact ended up doing real function calls in my tests, even though a compiler may optimize them out). - Its type-checked
(comparing as pointers makes the compiler warn if they don't match).