Ответ 5
TL; DR
Matthew answer о том, как логический оператор &&
- самая большая разница; логическое сравнение остановится, когда оно найдет что-то, что сломает цепочку. Кроме того, еще одна большая разница - это результат/значение результата.
Используя Logical And &&
, он всегда будет возвращать логический тип/значение, true
или false
.
false & 1 // int(0)
false && 1 // bool(false)
Важно использовать логический тип/значения при возврате функции с логическим результатом, потому что кто-то может использовать Оператор идентичного сравнения ===
для сравнения результатов (что очень вероятно, произойдет), и он потерпит неудачу, если вы используйте что-то вроде этого:
(false & 1) === false // bool(false)
(true & true) === true // bool(false)
Никогда не используйте побитовые и &
, когда вам нужно сделать логическое сравнение и особенно когда возвращаете значения из функций с логическими результатами. Вместо этого используйте логический и &&
:
(false && 1) === false // bool(true)
(true && true) === true // bool(true)
При сравнении символов логический и &&
всегда будут иметь значение true
, даже с символом NUL
, если только он не преобразуется в целое число:
'A' && 'B' // bool(true)
'A' && 0 // bool(false)
'A' && '\0' // bool(true)
'A' && (int)'\0' // bool(false)
Если вы используете побитовый и &
с символами, это приведет к тому, что символ, соответствующий операции "Побитовое и" между этими двумя символами:
'A' & 'B' // string(1) "@"
01000001 // ASCII 'A'
&
01000010 // ASCII 'B'
=
01000000 // ASCII '@'
Остерегайтесь использования Побитового и &
при использовании с типами, отличными от целых и символов (которые являются особыми типами целых чисел). Например, если вы используете его с действительными числами float/double, то это может привести к 0
, даже если оба операнда НЕ 0
:
1.0 & 1.0 // int(1)
2.0 & 1.0 // int(0)
1.0 && 1.0 // bool(true)
2.0 && 1.0 // bool(true)
Кроме того, если мы идем на уровне инструкций сборки, мы можем видеть эту разницу и то, как компилятор справляется с обработкой, поэтому логическое и &&
использует cmp <var>, 0
для сравнения и не выполняет выполнение, если один операнд выходит из строя; Побитовое И использует and <var1>, <var2>
для поразрядного результата, а затем проверяет, имеет ли значение 0
значение. Я знаю, что этот вопрос отмечен для php и php поведение может отличаться от c, но я буду использовать небольшой c, чтобы показать, как работает компилятор, когда используя логические и побитовые и.
Предположим, что у нас есть программа в c, который использует как побитовые, так и логические и:
int a = 0;
int b = 1;
int c = 2;
if (a & b)
c = 3;
if (a && b)
c = 4;
Компилятор сгенерирует следующие коды операций сборки (результат W32Dasm для x86, я изменил адреса памяти с именами <variable>
для простоты и стал более понятным):
:0229 mov <a>, 0
:0230 mov <b>, 1
:0237 mov <c>, 2
// if (a & b) begins
:023E mov eax, <a>
:0241 and eax, <b> // a bitwise and b, result stored to eax
:0244 test eax, eax // test eax and set ZeroFlag if equals to 0
:0246 je 024F // >--- Jump if ZeroFlag is set
:0248 mov <c>, 3 // | or set c = 3
// if (a && b) begins |
:024F cmp <a>, 0 // <--- compare a to 0 and sets ZeroFlag if difference is 0
:0253 je 0262 // >--- Jump if ZeroFlag is set (a == 0)
:0255 cmp <b>, 0 // | compare b to 0 and sets ZeroFlag if differemce is 0
:0259 je 0262 // | >--- Jump if ZeroFlag is set (b == 0)
:025B mov <c>, 4 // | | or set c = 4
:0262 <program continues> // <--- <---
Компилятор не только использует разные инструкции для сравнения между логическим и битвейзным а, но в логическом сравнении строки :0253
в if (a && b)
мы видим, что если a == 0
, то он перескакивает и не проверяет остальное операнды.
Итак, я не согласен с комментарием animuson:
Они оба одинаковы, они просто используются для двух разных вещи для выполнения той же задачи. - animuson Мар 4 '10 в 1:42
Это не одно и то же, и оба они/должны использоваться для конкретных задач в зависимости от логики/потока программ.