It’s been a while since I code in C. I remember how I struggled with the “bible”: C Programming Language when I was in college. I’m not sure it was a great choice as the first coding textbook for a college freshman who never coded before. I’ve never been a big fan of C ever since.
However I started to pick up C again recently and decided to give it another try as I grew interested in the embedded system and AIoT stuff. Today I encountered a very interesting challenge, how to swap two values in C. In Python or Javascript, this is so freaking simple
a, b= b, a
But in C, it’s a whole another story. I fired up my vi and type the following:
#include <stdio.h>
void swap(a, b){
int temp;
temp = a;
a = b;
b = temp;
}
int main(){
int a, b;
scanf("%d%d", &a, &b);
printf("before swap: a = %d, b = %d", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);
return 0
}
Unexpectedly, I failed as expected :) The results will be no swap, despite the introduction of temp
!
Pointers
Then I recalled something painful about pointers, addresses, so here’s another try of rewriting the swap
function
#include <stdio.h>
void swap(*a, *b){
int temp = *a;
*a = *b;
*b = temp;
}
int main(){
int a, b;
scanf("%d%d", &a, &b);
printf("before swap: a = %d, b = %d", a, b);
swap(&a, &b); // here we need to pass the addresses
printf("after swap: a = %d, b = %d\n", a, b);
return 0;
}
The output looks correct.
Macro
Yet, that’s not the end of the story. Defining a void swap function is fine, alternatively we could define and use a macro:
#include <stdio.h>
define swap(a,b){\
__typeof(a) __temp=a;\
a = b; b = __temp;\
}
int main(){
int a, b;
scanf("%d%d", &a, &b);
printf("a = %d, b = %d\n", a, b);
swap(a, b);
printf("swap: a = %d, b = %d\n", a, b);
return 0;
}
The macro provided uses the __typeof
keyword to declare a variable __temp
with the same type as a
. This ensures that the temporary variable used in the swap operation has the correct type.
XOR
Finally we can use the XOR swap algorithm to swap two integer values without using a temporary variable:
#include <stdio.h>
int main() {
int a, b;
printf("Enter two integer values to swap: ");
scanf("%d %d", &a, &b);
printf("Before swap: a = %d, b = %d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("After swap: a = %d, b = %d\n", a, b);
return 0;
}
The XOR swap algorithm works by taking advantage of the properties of the bitwise exclusive or (XOR) operator. When you XOR two values together, the result will be a new value that has the bits set to 1 wherever the corresponding bits in the original values differed.
So, to swap two values a
and b
using the XOR swap algorithm, we perform the following three operations:
- Set
a
toa ^ b
, which setsa
to the XOR of its original value andb
. - Set
b
toa ^ b
again, which setsb
to the XOR of the new value ofa
and its original value, effectively settingb
to the original value ofa
. - Set
a
toa ^ b
again, which setsa
to the XOR of its new value andb
, which is now equal to the original value ofa
, effectively settinga
to the original value ofb
.
Pretty cool, right?
Which is better?
The function approach is a runtime operation and incurs a function call overhead. However, modern compilers can often inline small functions like the swap
function we defined earlier, which can eliminate the function call overhead. The function approach is more flexible than the macro approach since it can handle different types of arguments being swapped.
The macro approach is a compile-time operation and does not incur any function call overhead. The code generated by the macro approach is often inlined by the compiler, which can result in efficient code. However, the macro approach requires that the types of the arguments being swapped are compatible, and it may not work correctly in all cases.
The XOR approach is a bitwise operation that can be faster than the macro or function approach on some architectures. The XOR approach avoids the need for a temporary variable by using bitwise XOR operations. However, the XOR approach requires that the values being swapped are of the same type and may not work correctly in all cases. Additionally, the XOR approach can be less readable than the macro or function approach.