Почему в 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
Ответы
Ответ 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, побитовый оператор ^
работает намного лучше...