Почему в C / C ++ нет оператора ^^? - PullRequest
16 голосов
/ 08 мая 2009

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

Я понимаю, что это не было бы коротким замыканием, но у него была бы другая семантика. В 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

Ответы [ 7 ]

54 голосов
/ 08 мая 2009

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

Существуют как исторические, так и практические причины, по которым нет оператора ^^.

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

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

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

24 голосов
/ 08 мая 2009

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

a != b

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

Edit:

Комментарий

Volte :

(!a) != (!b)

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

Снова отредактируйте:

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

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

5 голосов
/ 08 мая 2009

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

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

5 голосов
/ 08 мая 2009

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

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

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

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

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

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

1 голос
/ 08 мая 2009

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

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

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

1 голос
/ 08 мая 2009

Другой обходной путь для тех, которые опубликованы выше (даже если для этого требуется другая ветка в коде), будет:

if ( (a? !b : b ) )

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

0 голосов
/ 08 мая 2009

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

Конечно, любое целое число можно интерпретировать как истинное значение в C, в этом случае 0 равно «false», а все остальные значения «true», но это противоположно тому, что возвращает 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, побитовый оператор ^ также работает намного лучше ...

...