Подтвердить что ты не робот

Почему в C/С++ нет оператора ^^?

& имеет &&. | имеет ||. Почему ^ не имеет ^^?

Я понимаю, что это не будет короткое замыкание, но у него будет другая семантика. В C, true действительно любое ненулевое значение. Побитовое XOR не всегда совпадает с логическим XOR:

int a=strcmp(str1,str2);// evaluates to 1, which is "true"
int b=strcmp(str1,str3);// evaluates to 2, which is also "true"
int c=a ^^ b; // this would be false, since true ^ true = false
int d=a ^ b; //oops, this is true again, it is 3 (^ is bitwise)

Поскольку вы не всегда можете полагаться на истинное значение 1 или -1, не может ли быть полезным оператор ^^? Мне часто приходится делать такие странные вещи:

if(!!a ^ !!b) // looks strange
4b9b3361

Ответ 1

Деннис Ритчи отвечает

Есть и исторические, и практические причины, по которым нет оператора ^^.

Практически: для оператора мало пользы. Главной точкой && и || является использование их оценки короткого замыкания не только по соображениям эффективности, но чаще для выразительности и правильности.
[...]
Напротив, оператор ^^ всегда будет принудительно оценивать обе руки выражения, поэтому нет повышения эффективности. Кроме того, ситуации, в которых действительно вызван ^^, довольно редки, хотя примеры могут быть созданы. Эти ситуации становятся все реже и страннее, когда вы складываете оператора -

if (cond1() ^^ cond2() ^^ cond3() ^^ ...) ...

делает это в точности, когда нечетное число condx() истинно. Напротив, аналоги && и || остаются довольно правдоподобными и полезными.

Ответ 2

Технически, уже существует:

a != b

так как это будет оцениваться как true, если значение истинности операндов отличается.

Edit:

Volte комментарий:

(!a) != (!b)

правильно, потому что мой ответ выше не работает для типов int. Я удалю мою, если он добавит свой ответ.

Изменить еще раз:

Может быть, я забыл что-то из С++, но чем больше я думаю об этом, тем больше мне интересно, почему вы когда-нибудь пишете if (1 ^ 2) в первую очередь. Цель ^ состоит в объединении исключительных или двух чисел (которые оцениваются на другое число), а не преобразовывать их в логические значения и сравнивать их значения истинности.

Похоже, это было бы странным предположением для разработчика языка.

Ответ 3

Для операндов bool я предполагаю, что вы хотите, чтобы a ^^ b оценивался как:

(a != 0) ^ (b != 0)

Ну, у вас есть вышеуказанный вариант, и у вас есть несколько вариантов, перечисленных в других ответах.

Оператор ^^ будет лишним для операндов bool. Говоря только о логических операндах, ради аргумента, пусть притворяется, что ^ был только побитовым и что ^^ существовал как логический XOR. У вас есть следующие варианты:

  • & - Побитовое И - всегда оценивает оба операнда
  • && - Логический И - не всегда оценивает оба операнда
  • | - Побитовое ИЛИ - всегда оценивает оба операнда
  • || - Логический OR - не всегда оценивает оба операнда
  • ^ - Побитовое XOR - должно всегда оценивать оба операнда
  • ^^ - Логический XOR - должен всегда оценивать оба операнда

Почему они не создали ^^, чтобы по существу преобразовать числовые значения в bool, а затем действовать как ^? Это хороший вопрос. Возможно, потому что это более запутанно, чем && и ||, возможно потому, что вы можете легко построить эквивалент ^^ с другими операторами.

Ответ 4

Я не могу сказать, что было в головах Кернигана и Ричи, когда они изобрели C, но вы сделали краткую ссылку на "не будет короткого замыкания", и я предполагаю, что причина: это не его можно реализовать последовательно. Вы не можете закоротить XOR так, как вы можете AND и OR, поэтому ^^ не может полностью параллельна && и ||. Таким образом, авторы вполне могли решить, что создание операции похоже на ее параллель с другими, но не совсем было бы хуже, чем не иметь ее вообще.

Лично основная причина, по которой я использую && и || для короткого замыкания, а не для побитового. На самом деле я очень редко использую побитовые операторы вообще.

Ответ 5

Другим обходным путем к вышеперечисленным (даже если он требует другую ветвь в коде):

if ( (a? !b : b ) )

что эквивалентно xor.

Ответ 6

В Java оператор ^ действительно выполняет логический XOR при использовании в двух булевых операндах (точно так же, как & и | в Java не требует короткого замыкания логических И и ИЛИ соответственно, когда применяется к булевым). Основное отличие от C/С++ заключается в том, что C/С++ позволяет смешивать целые числа и логические значения, тогда как Java не делает.

Но я считаю, что плохая практика использовать целые числа как булевы в любом случае. Если вы хотите выполнять логические операции, вы должны придерживаться значений bool или целых чисел, которые равны 0 или 1. Затем ^ отлично работает как логический XOR.

Аналогичный вопрос заключается в том, чтобы спросить, как бы вы выполняли логику AND и OR с коротким замыканием в C/С++? Обычный ответ - использовать операторы & и | соответственно. Но опять же, это зависит от значений bool или 0 или 1. Если вы разрешаете любые целочисленные значения, то это также не работает.

Ответ 7

Независимо от случая для или против ^^ в качестве оператора, вы пример с strcmp() отстой. Он не возвращает значение истины (true или false), он возвращает отношение между его входами, закодированными как целое.

Конечно, любое целое число можно интерпретировать как значение истинности в C, и в этом случае 0 является "ложным", а все остальные значения "истинны", но это противоположно тому, что возвращает strcmp().

Ваш пример должен начинаться:

int a = strcmp(str1, str2) == 0; // evaluates to 0, which is "false"
int b = strcmp(str1, str3) == 0; // evaluates to 0, which is also "false"

Вы должны сравнить возвращаемое значение с 0, чтобы преобразовать его в правильное логическое значение, указывающее, были ли строки равными или нет.

С "правильными" булевыми элементами, представленными канонически как 0 или 1, побитовый оператор ^ работает намного лучше...