patterncppMajor
Swapping two integer numbers with no temporary variable
Viewed 0 times
temporarywithnumbersswappingtwovariableinteger
Problem
I tried to swap 2 integer numbers without using an additional variable as a traditional swap.
Is it legal in C++? My VC compiler doesn't complain nor gives any warning about it. If so, how can I improve this script?
For this code:
Assembler output for VC++ 2013:
For this code:
Assembler output for VC++ 2013:
Is it legal in C++? My VC compiler doesn't complain nor gives any warning about it. If so, how can I improve this script?
#include
int main()
{
int a = 20;
int b = 66;
// before swapping
std::cout << a << ' ' << b << '\n';
// swap
a ^= b ^= a ^= b;
// after swapping
std::cout << a << ' ' << b << '\n';
}For this code:
int a = 20;
int b = 66;
a ^= b ^= a ^= b;Assembler output for VC++ 2013:
_b$ = -20 ; size = 4
_a$ = -8 ; size = 4
mov DWORD PTR _a$[ebp], 20 ; 00000014H
mov DWORD PTR _b$[ebp], 66 ; 00000042H
mov eax, DWORD PTR _a$[ebp]
xor eax, DWORD PTR _b$[ebp]
mov DWORD PTR _a$[ebp], eax
mov ecx, DWORD PTR _b$[ebp]
xor ecx, DWORD PTR _a$[ebp]
mov DWORD PTR _b$[ebp], ecx
mov edx, DWORD PTR _a$[ebp]
xor edx, DWORD PTR _b$[ebp]
mov DWORD PTR _a$[ebp], edxFor this code:
int a = 20;
int b = 66;
int t = a;
a = b;
b = t;Assembler output for VC++ 2013:
_t$ = -32 ; size = 4
_b$ = -20 ; size = 4
_a$ = -8 ; size = 4
mov DWORD PTR _a$[ebp], 20 ; 00000014H
mov DWORD PTR _b$[ebp], 66 ; 00000042H
mov eax, DWORD PTR _a$[ebp]
mov DWORD PTR _t$[ebp], eax
mov eax, DWORD PTR _b$[ebp]
mov DWORD PTR _a$[ebp], eax
mov eax, DWORD PTR _t$[ebp]
mov DWORD PTR _b$[ebp], eaxSolution
You make assumptions which may not be true. Why do you believe that
actually is compiled down to using an actual variable? It is likely just a register used on the CPU.
Have you inspected it?
Further, why do you assume that:
uses fewer registers than a swap?
Really, what you should do is:
Which is also a reminder that having the
Update - assembler output
For the code:
you get the assembler output:
For the code:
you get
What does that show?
Net result? Both systems use less than 16 bytes of the stack, they both use 1 register in addition to the stack, and they both have the same number of instructions.
I know which one is more readable....
Of course, with the above code, if I add -O2 to the optimization, I get the assembler:
which, as you can imagine, is fast.
int tmp = a;
a = b;
b = tmp;actually is compiled down to using an actual variable? It is likely just a register used on the CPU.
Have you inspected it?
Further, why do you assume that:
a ^= b ^= a ^= b;uses fewer registers than a swap?
Really, what you should do is:
#include
#include
int main() {
int a = 20;
int b = 66;
// before swapping
std::cout << a << ' ' << b << '\n';
// swap
std::swap(a,b);
// after swapping
std::cout << a << ' ' << b << '\n';
}Which is also a reminder that having the
a ^= b ^= a ^= b; 'naked' in your code is not good practice. Something like that should be embedded in a function, not directly in the main method.Update - assembler output
For the code:
int a = 20;
int b = 66;
int t = a;
a = b;
b = t;
return a;you get the assembler output:
movl $20, -12(%rbp)
movl $66, -8(%rbp)
movl -12(%rbp), %eax
movl %eax, -4(%rbp)
movl -8(%rbp), %eax
movl %eax, -12(%rbp)
movl -4(%rbp), %eax
movl %eax, -8(%rbp)
movl -12(%rbp), %eax
popq %rbpFor the code:
int a = 20;
int b = 66;
a ^= b ^= a ^= b;
return a;you get
movl $20, -8(%rbp)
movl $66, -4(%rbp)
movl -4(%rbp), %eax
xorl %eax, -8(%rbp)
movl -8(%rbp), %eax
xorl %eax, -4(%rbp)
movl -4(%rbp), %eax
xorl %eax, -8(%rbp)
movl -8(%rbp), %eax
popq %rbpWhat does that show?
- It shows that both systems run in 12 instructions, including the copy to the stack (%rbp)
- that both systems use the single register %eax
- both systems use the stack as a temp store for the result (the XOR reuses -8 and -4 offsets in the stack, the tmp uses -12(%rbp)
Net result? Both systems use less than 16 bytes of the stack, they both use 1 register in addition to the stack, and they both have the same number of instructions.
I know which one is more readable....
Of course, with the above code, if I add -O2 to the optimization, I get the assembler:
movl $66, %eax
retwhich, as you can imagine, is fast.
Code Snippets
int tmp = a;
a = b;
b = tmp;a ^= b ^= a ^= b;#include <algorithm>
#include <iostream>
int main() {
int a = 20;
int b = 66;
// before swapping
std::cout << a << ' ' << b << '\n';
// swap
std::swap(a,b);
// after swapping
std::cout << a << ' ' << b << '\n';
}int a = 20;
int b = 66;
int t = a;
a = b;
b = t;
return a;movl $20, -12(%rbp)
movl $66, -8(%rbp)
movl -12(%rbp), %eax
movl %eax, -4(%rbp)
movl -8(%rbp), %eax
movl %eax, -12(%rbp)
movl -4(%rbp), %eax
movl %eax, -8(%rbp)
movl -12(%rbp), %eax
popq %rbpContext
StackExchange Code Review Q#76976, answer score: 21
Revisions (0)
No revisions yet.