Читать в оригинале

<< Предыдущая Оглавление Следующая >>


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

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

int k1 = 7;
if (k1) Console.WriteLine("ok!");

незаконна в программах на C#. На этапе трансляции возникнет ошибка, поскольку вычисляемое условие имеет тип int, а неявное преобразование этого типа к типу bool отсутствует.

В языке C# более строгие правила действуют и для логических операций. Так, запись     if(k1 && (x>y)), корректная в языке C++, приводит к ошибке в

программах на C#, поскольку операция && определена только для операндов типа bool, а в данном выражении один из операндов имеет тип int. В языке C# в данных ситуациях следует использовать записи:

if(k1>0)
if((k1>0) && (x>y))

Логические операции делятся на две категории: одни выполняются над логическими значениями операндов, другие осуществляют выполнение логической операции над битами операндов. По этой причине в C# существуют две унарные операции отрицания - логическое отрицание, заданное операцией «!», и побитовое отрицание, заданное операцией «~». Первая из них определена над операндом типа bool, вторая - над операндом целочисленного типа, начиная с типа int и выше (int, uint, long, ulong). Результатом операции во втором случае является операнд, в котором каждый бит заменен его дополнением. Приведем пример:

/// <summary>
/// Логические выражения
/// </summary>
public void Logic() {
          //операции отрицания ~, !
          bool b1, b2;
          b1 = 2*2 == 4;
          b2 =!b1;           
          //b2= ~b1;
          uint j1 = 7, j2;
           j2 = ~j1;
          //j2 = !j1;
          int j4 = 7, j5;
          j5 = ~j4;
       Console.WriteLine("uint j2 = " + j2 + " int j5 = " + j5);
} //Logic

В этом фрагменте закомментированы операторы, приводящие к ошибкам. В первом случае была сделана попытка применения операции побитового отрицания к выражению типа bool, во втором - логическое отрицание применялось к целочисленным данным. И то, и другое в C# незаконно. Обратите внимание на разную интерпретацию побитового отрицания для беззнаковых и знаковых целочисленных типов. Для переменных j5 и j2 строка битов, задающая значение - одна и та же, но интерпретируется по-разному. Соответствующий вывод таков:

uint j2 = 4294967288
int j5 = -8.

Бинарные логические операции «&& - условное И» и «|| - условное ИЛИ» определены только над данными типа bool. Операции называются условными или краткими, поскольку, вычисление второго операнда зависит от уже вычисленного значения первого операнда. Ценность условных логических операций заключается в их эффективности по времени выполнения. Часто они позволяют вычислить логическое выражение, имеющее смысл, но в котором второй операнд не определен. Приведем в качестве примера классическую задачу поиска по образцу в массиве, когда разыскивается элемент с заданным значением (образец). Такой элемент в массиве может быть, а может и не быть. Вот типичное решение этой задачи в упрощенном виде, но передающем суть дела:

//Условное And - &&
int[ ] ar = { 1, 2, 3 };
int search = 7;
int i = 0;
while ((i < ar.Length) && (ar[i] != search)) {
           i++;
}
if (i < ar.Length) Console.WriteLine("Образец найден");
else    Console.WriteLine("Образец не найден");

Если значение переменной search (образца) не совпадает ни с одним из значений элементов массива ar, то последняя проверка условия цикла while будет выполняться при значении i, равном ar.Length. В этом случае первый операнд получит значение false, и, хотя второй операнд при этом не определен, цикл нормально завершит свою работу. Второй операнд не определен в последней проверке, поскольку индекс элемента массива выходит за допустимые пределы (в C# индексация элементов начинается с нуля).

Три бинарные побитовые операции - «& - AND» , « | - OR», «^ - XOR» используются двояко. Они определены как над целыми типами выше int, так и над булевыми типами. В первом случае они используются как побитовые операции, во втором - как обычные логические операции. Иногда необходимо, чтобы оба операнда вычислялись в любом случае, тогда без этих операций не обойтись. Вот пример первого их использования:

//Логические побитовые операции And, Or, XOR (&,|,^)
int k2 = 7, k3 = 5, k4, k5, k6;
k4 = k2 & k3;
k5 = k2 | k3;
k6 = k2 ^ k3;
Console.WriteLine("k4 = " + k4 + " k5 = " + k5 + " k6 = " + k6);

Результаты вывода:

k4 = 5 k5 = 7 k6 =2

Приведем пример поиска по образцу с использованием логического AND: i = 0;

search = ar[ar.Length - 1];
while ((i < ar.Length) & (ar[i] != search)) i++;
if (i < ar.Length) Console.WriteLine("Образец найден");
else cConsole.WriteLine("Образец не найден");

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

 



<< Предыдущая Оглавление Следующая >>