This is called optimization:
Code:
#include <stdio.h>
void swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
void swap2(int* x, int* y)
{
*x ^= *y;
*y = *x ^ *y;
*x ^= *y;
}
int main()
{
int x = 3, y = 4;
int z = 4, w = 3;
swap(&x, &y);
swap2(&z, &w);
printf("x = %d, y = %d\n", x, y);
printf("z = %d, w = %d\n", z, w);
}
And assembly (phew, finally real asm, instead of that bloody gcc mess):
Code:
int main()
{
00951000 push esi
int x = 3, y = 4;
int z = 4, w = 3;
swap(&x, &y);
swap2(&z, &w);
printf("x = %d, y = %d\n", x, y);
00951001 mov esi,dword ptr [__imp__printf (9520A0h)]
00951007 push 3
00951009 push 4
0095100B push offset ___xi_z+34h (9520F4h)
00951010 call esi
printf("z = %d, w = %d\n", z, w);
00951012 push 4
00951014 push 3
00951016 push offset ___xi_z+44h (952104h)
0095101B call esi
0095101D add esp,18h
}
00951020 xor eax,eax
00951022 pop esi
00951023 ret
The compiler is pretty clever.
To force the compiler to execute the swap, let's read some numbers and see what it does:
Code:
#include <stdio.h>
void swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
void swap2(int* x, int* y)
{
*x ^= *y;
*y = *x ^ *y;
*x ^= *y;
}
int main()
{
int x = 3, y = 4;
int z = 4, w = 3;
printf("Enter 4 integers: ");
scanf("%d %d %d %d", &x, &y, &z, &w);
swap(&x, &y);
swap2(&z, &w);
printf("x = %d, y = %d\n", x, y);
printf("z = %d, w = %d\n", z, w);
}
And assembly:
Code:
int main()
{
00881000 sub esp,10h
00881003 push esi
int x = 3, y = 4;
int z = 4, w = 3;
printf("Enter 4 integers: ");
00881004 mov esi,dword ptr [__imp__printf (88209Ch)]
0088100A mov ecx,3
0088100F mov eax,4
00881014 push edi
00881015 push offset ___xi_z+30h (8820F4h)
0088101A mov dword ptr [esp+14h],ecx
0088101E mov dword ptr [esp+18h],eax
00881022 mov dword ptr [esp+10h],eax
00881026 mov dword ptr [esp+0Ch],ecx
0088102A call esi
scanf("%d %d %d %d", &x, &y, &z, &w);
0088102C lea eax,[esp+0Ch]
00881030 push eax
00881031 lea ecx,[esp+14h]
00881035 push ecx
00881036 lea edx,[esp+20h]
0088103A push edx
0088103B lea eax,[esp+20h]
0088103F push eax
00881040 push offset ___xi_z+44h (882108h)
00881045 call dword ptr [__imp__scanf (8820A4h)]
swap(&x, &y);
swap2(&z, &w);
0088104B mov edx,dword ptr [esp+20h]
0088104F mov eax,dword ptr [esp+28h]
00881053 mov ecx,dword ptr [esp+24h]
00881057 mov edi,dword ptr [esp+2Ch]
0088105B xor ecx,edx
printf("x = %d, y = %d\n", x, y);
0088105D push eax
0088105E xor edx,ecx
00881060 xor ecx,edx
00881062 push edi
00881063 push offset ___xi_z+50h (882114h)
00881068 mov dword ptr [esp+34h],edi
0088106C mov dword ptr [esp+38h],eax
00881070 mov dword ptr [esp+2Ch],edx
00881074 mov dword ptr [esp+30h],ecx
00881078 call esi
printf("z = %d, w = %d\n", z, w);
0088107A mov ecx,dword ptr [esp+2Ch]
0088107E mov edx,dword ptr [esp+30h]
00881082 push ecx
00881083 push edx
00881084 push offset ___xi_z+60h (882124h)
00881089 call esi
0088108B add esp,30h
0088108E pop edi
}
0088108F xor eax,eax
00881091 pop esi
00881092 add esp,10h
00881095 ret
(Interesting part bolded.)
To separate the two functions calls apart to see what it does, we use a slightly different code:
Code:
#include <stdio.h>
void swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
void swap2(int* x, int* y)
{
*x ^= *y;
*y = *x ^ *y;
*x ^= *y;
}
int main()
{
int x = 3, y = 4;
int z = 4, w = 3;
printf("Enter 4 integers: ");
scanf("%d %d %d %d", &x, &y, &z, &w);
swap(&x, &y);
printf("x = %d, y = %d\n", x, y);
swap2(&z, &w);
printf("z = %d, w = %d\n", z, w);
}
And the assembly:
Code:
int main()
{
00031000 sub esp,10h
00031003 push esi
int x = 3, y = 4;
int z = 4, w = 3;
printf("Enter 4 integers: ");
00031004 mov esi,dword ptr [__imp__printf (3209Ch)]
0003100A mov ecx,3
0003100F mov eax,4
00031014 push offset ___xi_z+30h (320F4h)
00031019 mov dword ptr [esp+8],ecx
0003101D mov dword ptr [esp+0Ch],eax
00031021 mov dword ptr [esp+14h],eax
00031025 mov dword ptr [esp+10h],ecx
00031029 call esi
scanf("%d %d %d %d", &x, &y, &z, &w);
0003102B lea eax,[esp+10h]
0003102F push eax
00031030 lea ecx,[esp+18h]
00031034 push ecx
00031035 lea edx,[esp+14h]
00031039 push edx
0003103A lea eax,[esp+14h]
0003103E push eax
0003103F push offset ___xi_z+44h (32108h)
00031044 call dword ptr [__imp__scanf (320A4h)]
swap(&x, &y);
0003104A mov eax,dword ptr [esp+1Ch]
0003104E mov ecx,dword ptr [esp+20h]
printf("x = %d, y = %d\n", x, y);
00031052 push eax
00031053 push ecx
00031054 push offset ___xi_z+50h (32114h)
00031059 mov dword ptr [esp+28h],ecx
0003105D mov dword ptr [esp+2Ch],eax
00031061 call esi
swap2(&z, &w);
00031063 mov ecx,dword ptr [esp+30h]
00031067 mov eax,dword ptr [esp+34h]
0003106B xor eax,ecx
0003106D xor ecx,eax
0003106F xor eax,ecx
printf("z = %d, w = %d\n", z, w);
00031071 push ecx
00031072 push eax
00031073 push offset ___xi_z+60h (32124h)
00031078 mov dword ptr [esp+3Ch],ecx
0003107C mov dword ptr [esp+40h],eax
00031080 call esi
00031082 add esp,30h
}
00031085 xor eax,eax
00031087 pop esi
00031088 add esp,10h
0003108B ret
Again, the interesting parts bolded.
Actually, as we see, the compiler actually created somewhat more efficient code for the first swap, I'd say.
This was using Visual Studio 2008 (compiled as C++ with all optimizations enabled).
Hope this gives some interesting data.