Можно ли сравнить два логических значения в C ++? - PullRequest
6 голосов
/ 03 февраля 2010

Должен ли работать следующий фрагмент кода?

bool b1 = true;
bool b2 = 1 < 2;
if (b1 == b2)
{
// do something
}

Я подозреваю, что не все "истины" равны.

Ответы [ 8 ]

18 голосов
/ 03 февраля 2010

Да. Все истины равны.

11 голосов
/ 03 февраля 2010

Да, логические значения могут хранить только истину или ложь, и вы можете сравнить значения на равенство.

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

Взгляните на следующий (плохой) пример:

  bool b1 = true; 
  bool b2 = true; 
  *((char*)&b1) = 3;

  if( b1 ) cout << "b1 is true" << endl;
  if( b2 ) cout << "b2 is true" << endl;
  if (b1 != b2) cout << "b2 is not equal to b1" << endl;

В Visual Studio 9 отображается:

b1 верно

b2 верно

b2 не равно b1

Возможно, потому что компилятор напрямую сравнивает сохраненные значения.

7 голосов
/ 03 февраля 2010

Да, как уже говорили другие, можно сравнивать bools на равенство в C ++. Вы можете думать о вещах, которые вы слышали от C. Поскольку C не имеет типа bool, логические значения представляются как целые числа. В логическом контексте любое ненулевое целое число истинно. Однако они могут иметь разные битовые комбинации и, следовательно, не быть равными. Таким образом, правило в C не должно сравнивать «логические значения».

Редактировать: согласно комментариям, C99 имеет тип bool. Однако смысл ответа состоял в том, чтобы указать , почему витает идея не сравнивать bools. Он основан на долгой истории C, до C99.

2 голосов
/ 03 февраля 2010

Когда вы присваиваете интегральное значение логическому объекту (или инициализируете логический объект интегральным значением), оно неявно преобразуется в true или false стандартным логическим преобразованием (4.12).Таким образом, с языковой точки зрения ваши 1 и 2 остались без следа задолго до того, как вы даже сделаете сравнение.Они оба стали одинаковыми true.Здесь нет вопроса "все истины равны".Есть только один true.

Конечно, некоторые компиляторы могут, вероятно, использовать «ленивый» подход и держать несколько разных «истин», удостоверяясь, что они «все равны» в момент сравнения итакой, но я сомневаюсь, что это разумный / жизнеспособный подход.

Другими словами, в разумной реализации вы должны ожидать, что не только ваше сравнение будет верным, но и намного более сильное сравнение, чтобы быть верным:

bool b1 = true; 
bool b2 = 1 < 2;
if (memcmp(&b1, &b2, sizeof(bool)) == 0) {
  /* We should get in here */
}

Это не гарантируется языком, но в реальной жизни он достаточно хорошо описывает физическую сторону ситуации.

1 голос
/ 03 февраля 2010

В C ++ bool - это его собственный тип с двумя возможными значениями true и false. Все сравнения пойдут так, как вы ожидаете. Все true логические значения одинаковы и одинаковы для всех false. Это правда, что не все выражения, которые вы можете оценить как true или false, одинаковы.

В C89, чтобы вернуться так далеко, как я хочу, любое нулевое значение (любого указателя или числового типа) является ложным, а все остальное - истинным. Это означает, что истинные значения не обязательно равны друг другу. 1 и 2 являются истинными значениями, но 1 != 2 и 1 & 2 оцениваются в 0, что ложно.

Возможно также, что ложные значения C89 не будут сравниваться одинаково, хотя они будут в каждой реализации, которую я когда-либо использовал. Значение нулевого указателя является постоянным целым нулем, приведенным к значению указателя. Возможно, что непостоянное значение 0, приведенное к значению указателя, не будет нулевым указателем (и были системы, в которых нулевые указатели не были всеми битами 0). Следовательно, (void *)0 является нулевым значением указателя и, следовательно, ложным, но int i;...i = 0;...(void *)i не может быть нулевым значением указателя и, следовательно, не ложным.

Однако в C89 все операции, которые намереваются вернуть логическое значение (например, && или ==), вернут 1 или 0, так что (1 == 3) == (4 ==3).

1 голос
/ 03 февраля 2010

В C с int s у вас может быть точка (хотя даже там я думаю, что эта конкретная последовательность будет в порядке).В C ++ да, это безопасно.

0 голосов
/ 16 июня 2015

Я читал все эти ответы о том, почему true - это правда, и почему две булевы переменные можно сравнивать, используя == или !=, за исключением редких случаев, когда целое число приводится к значению типа bool или что-то подобное , Однако у меня точно такая же проблема, как у оригинального постера. У меня есть две логические переменные, каждая из которых 'true', но когда я сравниваю их, я обнаруживаю, что они не равны. Вот строка кода,

if (angDegDiff > 15 || scaleRatioA > 5 || scaleRatioB < -5 || (isParallel2 != isParallel1)) { return false; }

В моем примере angDegDiff = 0, scaleRatioA = 0, scaleRatioB = 0, isParallel2 = true и isParallel1 = true. Тем не менее, оператор оценивается как true, и единственный способ сделать это, если isParallel2 не равен isParallel1.

Не используются причудливые методы для установки значений isParallel1 или isParallel2. Их значения устанавливаются таким оператором, как _isParallel = true;. Позже это значение копируется в другую переменную с помощью оператора, такого как isParallel1 = geom1->IsParallel();, который реализуется как return _isParallel;.

Мой вывод заключается в том, что в зависимости от компилятора две логические переменные не могут быть надежно сопоставлены на равенство. Я использую Microsoft Visual C ++ 2005, версия 8.0.50727.4039.

Эпилог: я заменил логическое сравнение в своем коде на выражение ((isParallel1 && !isParallel2) || (!isParallel1 && isParallel2)), и теперь все работает нормально.

0 голосов
/ 03 февраля 2010

Проблемы только в том случае, если вы привыкли к ненулевым, будучи истинными, и забыли, что не все ненулевые равны

Представьте себе это:

У вас есть функция keyPressed (), которая возвращает 0 при отсутствии нажатия клавиши, номер клавиши при нажатии клавиши.

Вы написали простой переключатель в цикле:

if(keyPressed() && allow)
...

Теперь ваша компания вводит в устройства нормально открытые триггеры, и вам нужен преф.

bool key_switches_on = getPref("KeySwitchesOn");

if((keyPressed() && allow) == key_switches_on)
...

Тогда вы замечаете, что слово "allow" введено неправильно ...

if((keyPressed() == key_switches_on) && allow)

и вдруг работает только ключ номер 1.

...