Перейти к содержанию
  • записи
    104
  • комментариев
    125
  • просмотров
    15 687

[Lua] Логические операторы


MasterGH

1 464 просмотра

Существует три логических оператора: and, or, not.

Те, кто уже знаком с языками программирования знают, как эти логические операторы работают.

Например, 

    A = true
    B = true    
    if A and B then print('Условие "A and B" выполняется') end    
    if A or B then print('Условие "A or B" выполняется') end    
    B = false
    if not (B == A) then print('Условие "not (B == A)" выполняется') end

 

Но, дальше интереснее.

  1.     Все логические операторы считают false и nil ложными, а все остальное — истинными
  2.     Оператор "and" возвращает свой первый аргумент, если он ложен и в противном случае возвращается второй аргумент
  3.     Оператор "or" возвращает свой первый аргумент, если он не равен false и в противном случае возвращается второй аргумент.

 

Сходу можно запутаться, но с примерами станет понятнее

 

  print (4 and 5) --> "5". В этом примере '4" не ложный, а значит при операторе "and" вернется второй аргумент "5".
  print(0 and 13) --> "0". Аналогично
  print(false and 13) --> "false". В этом примере первый аргумент false(ложный), а значит при операторе and вернется "false".

  

  print(4 or 5)  --> "4"  В этом примере "4" не ложный, а значит при операторе "or" вернется уже первый аргумент "4".
  print(false or 5) --> "5" В этом примере "false" ложный, а значит при операторе "or" вернется уже первый аргумент "5".

  
  Если кто вспомнил, то в C# есть такой оператор "?" (условный) 

  string result = 4 == 4 ? "равно" : "не равно";  // result будет равен true


   На Lua это эквивалентно 

  local result = ( (4 == 5 and "равно") or "не равно")

  
  А если опустить все скобки, то 
 

local result = 4 < 5 and "равно" or "не равно".

  
 Скобки можно опустить, потому что "and" имеет выше приоритет чем "or."

 

Или вот еще пример

compactmenuitem.Caption = state and 'Compact View Mode' or 'Full View Mode'

 

  Вот такая интересная штука для ускоренного сравнения вместо конструкции
  

  if условие then
    -- код
  else
    -- код
  end

  
  Идем дальше. Полезной идиомой Lua является 
  

  x = x or v

 

  что эквивалентно 
  

  if not х then 
     х = v 
  end

  
  Т. е. x равен значению v, когда x ложное.
  

Оператор "not" всегда возвращает true или false 

    print(not nil)      --> true
    print(not false)    --> true
    print(not 0)        --> false
    print(not not nil)  --> false


 

  • Плюс 2

5 Комментариев


Рекомендуемые комментарии

А я с оператором OR никак не мог разобраться.

Цитата

 Оператор "or" возвращает свой первый аргумент, если он не равен false и в противном случае возвращается второй аргумент.

В качестве аргумента выступает все выражение до следующего слева/справа опреатора OR, если таковой имеется, или до начала/конца выражения. Так ведь?

А то я думал что только до первой переменной слева/справа.

 

Disassembler показывает, что происходит на самом деле.

Спойлер
Спойлер
int main() {
    int v1 = 1;
    int v2 = 1;
    int v3 = 1;
    int v4 = 0;
    int v5 = 1;
    if (v1 && v2 && v3 || v4 && v5) {
        std::wcout << L"work";
    }
    return 0;
}

 

Спойлер
    int v1 = 1;
00FC2605  mov         dword ptr [v1],1  
    int v2 = 1;
00FC260C  mov         dword ptr [v2],1  
    int v3 = 1;
00FC2613  mov         dword ptr [v3],1  
    int v4 = 0;
00FC261A  mov         dword ptr [v4],0  
    int v5 = 1;
00FC2621  mov         dword ptr [v5],1  
    if (v1 && v2 && v3 || v4 && v5) {
00FC2628  cmp         dword ptr [v1],0  
00FC262C  je          __$EncStackInitStart+4Eh (0FC263Ah)  
00FC262E  cmp         dword ptr [v2],0  
00FC2632  je          __$EncStackInitStart+4Eh (0FC263Ah)  
00FC2634  cmp         dword ptr [v3],0  
00FC2638  jne         __$EncStackInitStart+5Ah (0FC2646h)  
00FC263A  cmp         dword ptr [v4],0  
00FC263E  je          __$EncStackInitStart+6Dh (0FC2659h)  
00FC2640  cmp         dword ptr [v5],0  
00FC2644  je          __$EncStackInitStart+6Dh (0FC2659h)  
        std::wcout << L"work";
00FC2646  push        offset string L"work" (0FC9B30h)  
00FC264B  mov         eax,dword ptr [__imp_std::wcout (0FCD098h)]  
00FC2650  push        eax  
00FC2651  call        std::operator<<<wchar_t,std::char_traits<wchar_t> > (0FC1226h)  
00FC2656  add         esp,8  
    }
    return 0;

 

 

 

Ссылка на комментарий

>> В качестве аргумента выступает все выражение до следующего слева/справа опреатора

Нет-нет. В данном случае так не может быть, потому что нет скобок. Все идет последовательно как в дизассемблере.

 

С учетом таблицы приоритетов операторов в C++ "&&" выше || и с учетом твоего дизассемблерного  исходника в выражении (v1 && v2 && v3 || v4 && v5) идет последовательно


Сначала так

v1 && v2 — это истина.

 

Затем идет

истина && V3 — это истина. 

 

Затем программа видит Or  и дальше не пойдет, потому что от OR слева равно true (или не false). Так написано в официальной документации (что если слева от Or идет true, то дальше не идет) и так и видно по дизассемблерному исходнику на 

00FC2638  jne         __$EncStackInitStart+5Ah (0FC2646h)  

 

Вот еще пример

На плюсах ошибка "int Z = X + (A == B) ? 1 : 2" 

 

Т.е. программист хотел так "int Z = X + (A == B ? 1 : 2)", а сработает это вот так "int Z = (X + (A == B)) ? 1 : 2;". Похоже про то, что ты написал — все выражение слева.

 

Почему выражение целиком оборачивается слева? Наверно, потому что тернарный оператор этот "?:" имеет меньший приоритет чем + и == стоящих слева. Вот компилятор и посчитал собрать всю левую часть, как в скобки сам. Но, не уверен, что это так. В общем надо смотреть дизассебмлер.

Ссылка на комментарий
2 часа назад, MasterGH сказал:

>> В качестве аргумента выступает все выражение до следующего слева/справа опреатора

Нет-нет. В данном случае так не может быть, потому что нет скобок. Все идет последовательно как в дизассемблере.

 

Что если взять вот такой пример

Спойлер
int main() {
    INT v1 = 0;
    INT v2 = 1;
    INT v3 = 1;
    INT v4 = 1;
    INT v5 = 1;
    if (v1 && v2 && v3 || v4 && v5) {
        std::wcout << L"this work";
    }

    return 0;
}

 

 

Так как v1 равно 0, значит по правилам v2 не будет проверяться. Проверка перейдет на v4.  Это показывает и дизассемблер

Спойлер
    INT v1 = 0;
006C1D95  mov         dword ptr [v1],0  
    INT v2 = 1;
006C1D9C  mov         dword ptr [v2],1  
    INT v3 = 1;
006C1DA3  mov         dword ptr [v3],1  
    INT v4 = 1;
006C1DAA  mov         dword ptr [v4],1  
    INT v5 = 1;
006C1DB1  mov         dword ptr [v5],1  
    if (v1 && v2 && v3 || v4 && v5) {
006C1DB8  cmp         dword ptr [v1],0  
006C1DBC  je          __$EncStackInitStart+4Eh (06C1DCAh)  
006C1DBE  cmp         dword ptr [v2],0  
006C1DC2  je          __$EncStackInitStart+4Eh (06C1DCAh)  
006C1DC4  cmp         dword ptr [v3],0  
006C1DC8  jne         __$EncStackInitStart+5Ah (06C1DD6h)  
006C1DCA  cmp         dword ptr [v4],0  
006C1DCE  je          __$EncStackInitStart+6Dh (06C1DE9h)  
006C1DD0  cmp         dword ptr [v5],0  
006C1DD4  je          __$EncStackInitStart+6Dh (06C1DE9h)  
        std::wcout << L"this work";
006C1DD6  push        offset string L"this work" (06C9B30h)  
006C1DDB  mov         eax,dword ptr [__imp_std::wcout (06CD098h)]  
006C1DE0  push        eax  
006C1DE1  call        std::operator<<<wchar_t,std::char_traits<wchar_t> > (06C1226h)  
006C1DE6  add         esp,8  
    }

    return 0;

 

Значит OR проверяет все что слева (v1 && v2 && v3). А вернее сказать считается, со всем что слева. Ведь v3 здесь true, а значит то что правее OR по правилам проверяться не должно. Однако же оно проверяется, потому что OR считается не только с v3, но и с v1 и v2.

Вот, а я просто думал что OR считается только с v3, только с чем то одним..

 

 

Ссылка на комментарий

Я в прошлом посте чуть опечатался. Исправил.

 

Верно. С "or" будет работать как с таким выражением

 

( (v1 && v2 && v3) || (v4 && v5) )

(левая часть) || (правая часть)

 

Левая часть перестанет проверяться при первом false иначе пройдет до OR и прыгнет на успех в 6C1DD6.

Левая часть, если встретит false, то перескочит на проверку правой части.

Правая часть должна пройти все проверки до успеха в адрес 6C1DD6 иначе выход.

 

 

 

  • Плюс 1
Ссылка на комментарий
2 часа назад, MasterGH сказал:

Верно. С "or" будет работать как с таким выражением

 

( (v1 && v2 && v3) || (v4 && v5) )

(левая часть) || (правая часть)

 

Левая часть перестанет проверяться при первом false иначе пройдет до OR и прыгнет на успех в 6C1DD6.

Левая часть, если встретит false, то перескочит на проверку правой части.

Правая часть должна пройти все проверки до успеха в адрес 6C1DD6 иначе выход.

Спасибо что помог до конца разобраться.

  • Плюс 1
Ссылка на комментарий

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

Вы сможете оставить комментарий после входа в



Войти
×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.