Потенциальная проблема в "Обмен значениями двух переменных без использования третьей переменной"
Недавно я пришел к этому методу для замены значений двух переменных без использования третьей переменной.
a^=b^=a^=b
Но когда я попробовал вышеуказанный код на разных компиляторах, я получил разные результаты, некоторые дали правильные результаты, а некоторые не сделали.
Что-то ужасно неправильно с кодом?
Ответы
Ответ 1
Что-то ужасно неправильно с кодом?
Да!
a^=b^=a^=b
фактически вызывает Undefined Поведение в C и в С++, потому что вы пытаетесь изменить значение a
более одного раза между двумя точками последовательности.
Попробуйте написать (хотя и не надежный)
a ^= b;
b ^= a;
a ^= b;
вместо a^=b^=a^=b
.
P.S: никогда не пытайтесь менять значения двух переменных без использования третьего. Всегда используйте третью переменную.
ИЗМЕНИТЬ:
Как заметил @caf b^=a^=b
, даже если порядок оценки аргументов оператора ^=
не указан, поскольку все обращения b
в выражении используются для вычисления конечного значения, которое хранится в b
, поведение хорошо определено.
Ответ 2
Если вы используете С++, почему бы не использовать алгоритм подкачки в STL? Он идеален для этой цели, и очень ясно, что он делает:
#include <algorithm>
using namespace std;
// ...
int x=5, y=10; // x:5 y:10
swap(x,y); // x:10 y:5
Ответ 3
Основываясь на материалах R. и sellibitze:
Используйте оператор запятой:
(a^=b,b^=a,a^=b);
Из текста и Википедии:
"Оператор запятой может использоваться для связывания связанных выражений вместе. Список выражений, связанных с запятой, оценивается слева направо, а значение самого правого выражения - это значение комбинированного выражения. Оно действует как точка последовательности".
"Точка последовательности гарантирует, что все побочные эффекты предыдущих оценок будут выполнены, и никаких побочных эффектов от последующих оценок еще не было выполнено. Это устраняет поведение undefined, возникающее из-за нечеткого порядка выполнения оригинала выражение".
Ответ 4
Я предлагаю вам использовать std:: swap() для С++.
Для c используйте этот макрос. Обратите внимание, что сначала вам нужно сравнить a и b, иначе, когда они укажут на одно и то же место памяти, вы уничтожите значение и оно станет 0.
#define swap(a, b) ((a) == (b) || (a) ^= (b), (b) ^= (a), (a) ^= (b))
Ответ 5
Сделайте это так:
a ^= b;
b ^= a;
a ^= b;
Ответ 6
Как насчет этого?
a = a + b;
b = a - b;
a = a - b;
Ответ 7
Я задавался вопросом, почему никто не предлагал заключить в скобки выражение. Кажется, это не UB больше.
a^=(b^=(a^=b));
Ответ 8
Вы также можете попробовать следующее, но если для чисел достаточно большое значение будет переполняться
a=a*b;
b=a/b;
a=a/b;