Шаг 14.
Логические операции

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

    Перечислим теперь логические операции:

    Операция отрицания ! преобразует ненулевой ("истинный") операнд в 0, а нулевой ("ложный") операнд в 1. Например, можно использовать запись !inword вместо inword==0.

    Логическая операция "И" возвращает значение "истина", если оба ее операнда имеют значение "истина", иначе она вырабатывает значение "ложь".

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

    Пример 1. Иллюстрация применения логических операций и операций увеличения.

   #include<iostream.h>
   main ()
   {
      int x=1,y=1,z=0;
      x = x&&y||z;                           /* Операции 1 */
      cout<<x<<" ";
      x = x || !y&&z;                        /* Операции 2 */
      cout<<x<<" ";
      x = y=1; z = x++-1;                    /* Операции 3 */
      cout<<x<<" "<<z<<" ";
      z += -x++ + ++y;                       /* Операции 4 */
      cout<<x<<" "<<z<<" ";
      z = x/++x;                             /* Операции 5 */
      cout<<x<<" "<<z<<" ";
   }
Текст этой программы можно взять здесь.

Результат работы программы:

     1  1  2  0  3  0  4  1

    Прокомментируем полученные результаты.


    Операции 1
    int x=1, y=1, z=0;
    x=x&&y||z;

Сопоставляем операции с операндами в соответствии с приоритетами операций.

   x = (x&&y)||z;
   x = ((x&&y)||z);
   (x = (x&&y)||(z));

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

   (x = ((TRUE&&TRUE)||(z));
   (x = (TRUE||z);

    Если известно, что один из операндов логической операции "ИЛИ" (||) имеет значение "истина", то результат операции - "истина", независимо от значения другого операнда. Таким образом, в данном случае нет смысла продолжать вычисления дальше.

   (x = TRUE);
   1


    Операции 2
     x=1; y=1; z=0;
     x = x || !y&&z;

Сопоставляем операции с операндами в соответствии с приоритетами операций.

   x = x||!y&&z;
   x = x||(!y)&&z;
   x = x||((!y)&&z);
   (x = (x||(!y)&&(z)));

    Вычисляем слева направо:

   (x = (TRUE||((!y)&&z)));
   (x = TRUE);
   (x = 1);
   1


    Операции 3
     x = y=1; z = x++-1;

Вследствие приоритетов операций:

   z = x++-1;
   z = (x++)-1;
   z = ((x++)-1);
   (z = ((x++)-1));

    Операция ++, стоящая справа от операнда, представляет собой постфиксную операцию. Это означает, что x увеличится на 1 после того, как значение x будет использовано в выражении:

   (z = (1-1)); x = 2;
   (z = 0)
   0


    Операции 4
   x=2; y=1; z=0;
   z += -x++ + ++y;

    Унарные операции выполняются справа налево, так что операция ++ выполнится перед операцией -.

   z += -(x++) + (++y);

    Фактически, если бы операция изменения знака выполнялась первой, выражение было бы некорректным, так как операции ++ и -- требуют, чтобы операндом было адресное значение; x есть адресное значение, а -x нет.

   z += (-(x++)) + (++y);
   z += ((-(x++)) + (++y));
   (z += ((-(x++)) + (++y)));

    Вычисление выражения начинается изнутри:

   (z += ((-2)+2)); x = 3; y = 2;
   (z += 0);
   0


    Операции 5
   x=3; z=0;
   z = x/++x;
   z = x/(++x);
   z = (x/(++x));
   (z = (x/(++x)));

    При реализации этой программы мы получим z=1. Вы могли бы поддаться искушению вычислять это выражение "изнутри". Вначале было бы выбрано значение x, увеличено на 1, а потом уже пойдет деление на значение x. Но возникает вопрос: какое значение x нужно использовать в качестве делимого - старое (3) или новое (4)? Иными словами, что делается раньше - выбирается ли значение x, используемое в качестве делимого, или в x записывается его значение, увеличенное на 1. Описание языка C++ не определяет, что получается, если возникают такие побочные эффекты; их реализация остается за разработчиками трансляторов.

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

    Отсюда - совет: избегайте выражений, вычисление которых зависит от вашего знания того, что происходит при побочных эффектах.

    Мы закончили изложение логических операций. Следующий шаг будет посвящен битовым операциям.


Предыдущий шаг Содержание Следующий шаг