Is there a built-in way to swap two variables in C

后端 未结 10 1521
夕颜
夕颜 2020-12-01 14:53

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

相关标签:
10条回答
  • 2020-12-01 15:17

    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.

    0 讨论(0)
  • 2020-12-01 15:19

    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.

    0 讨论(0)
  • 2020-12-01 15:20

    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.

    0 讨论(0)
  • 2020-12-01 15:21

    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.

    0 讨论(0)
提交回复
热议问题