Формально оба метода используют всего три операции. Или не три? Решил проверить - просто подсмотреть, сколько инструкций ассемблера реально использует каждый из методов.
Реализовал оба метода (хотя для трех и одной строчки кода "реализовал" - громкое слово). Пометил обе переменные как volatile для того, чтобы компиляторы не удаляли неиспользуемые переменные. Прогнал через два компилятора (gcc и Microsoft Visual C++ 6.0) c ключами оптимизации по скорости. Результат свел в таблицу.
"swap" technique tests
Method 1 | Method 2 | |
---|---|---|
C source code | void test( ) | void test( ) |
MsVC 6.0 assembly output [cl /c /O2 /Fatest.asm test.c] | _test PROC NEAR ; COMDAT | _test PROC NEAR ; COMDAT |
GCC 3.4.4 assebly output [gcc.exe -S -O3 test.c] | _test: | _test: |
Число инструкций для первого метода - 4 для обоих компиляторов. Для второго - 12, то есть в три (!!!) раза больше. Правда, из этих двенадцати три инструкции оперируют только регистрами, но, в общем, это не спасает.
Конечно, тесты довольно искусственные, но, в общем, похоже, что использование блока кода
int a, b;
...
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
...
дает значительный выигрыш по сравнению с использованием строчки
a ^= b ^= a ^= b;
И при этом памяти используется ничуть не больше.
То есть, данная строчка является не более чем программерскими понтами. =)
Кстати, реализация swap вручную дала бы выигрыш всего в одну инструкцию:
mov eax, DWORD PTR _a$[esp+4]
xchg eax, DWORD PTR _b$[esp+4]
mov DWORD PTR _a$[esp+4], eax
6 комментариев: