Потенциальная проблема в "Обмен значениями двух переменных без использования третьей переменной"

Недавно я пришел к этому методу для замены значений двух переменных без использования третьей переменной.

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;