2009-07-01 2 views
27

Это чисто педантичный вопрос, чтобы удовлетворить свое любопытство.«Если ([bool] == true)« требуется еще один шаг, чем «if ([bool])»?

Я, как правило, уезжаю с последним вариантом в вопрос (так: if (boolCheck) { ... }), а коллега всегда пишет первый (if (boolCheck == true) { ... }). Я всегда его дразнил, и он всегда объяснял это как старую привычку, когда он начинал программировать.

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

Другими словами, как я понимаю, вариант без == истинная линия может быть свободно описана следующим образом:

  1. Проверить X

Хотя вариант с == истинная линия будет больше похожа:

  1. Пусть Y истинно, если X истинно, otherwi себе ложные
  2. Проверить Y

Am Я правильно? Или, может быть, любой нормальный компилятор/интерпретатор покончит с этим различием? Или я что-то пропускаю, и на самом деле нет никакой разницы?

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

EDIT: Спасибо всем, кто действительно опубликовал скомпилированные результаты, чтобы проиллюстрировать, были ли разные шаги между этими двумя подходами. (Кажется, большую часть времени они были, хотя и незначительно.)

Я просто хочу повторить, что я был не, спрашивая, что такое «правильный» подход. Я понимаю, что многие люди предпочитают друг друга. Я также понимаю, что, по логике, они идентичны. Мне было просто интересно, если фактические операции, выполняемые CPU, равны точно таким же для обоих методов; как выясняется, большую часть времени (очевидно, это зависит от языка, компилятора и т. д.), это не так.

+3

Это зависит от языка. На некоторых языках два условия на самом деле не совпадают. Например, в C (с #define true 1), "if (3) return;" возвращает, но "if (3 == true) return:" does not. – UncleO

+0

С другой стороны, с #define false 0, «boolCheck! = False» и «boolCheck» имеют тот же эффект, что и условия. – UncleO

+2

@uncleo: Вот почему TRUE не определяется как 1. Он определяется как (! FALSE). –

ответ

13

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

Редактировать: Самый простой способ рассказать - попробовать. МС компилятор (cl.exe) формирует одинаковое количество шагов в сборке:

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    bool test_me = true; 

    if (test_me) { 
004113C2 movzx  eax,byte ptr [test_me] 
004113C6 test  eax,eax 
004113C8 je   wmain+41h (4113E1h) 
     printf("test_me was true!"); 
    } 

    if (test_me == true) { 
004113E1 movzx  eax,byte ptr [test_me] 
004113E5 cmp   eax,1 
004113E8 jne   wmain+61h (411401h) 
     printf("still true!"); 
    } 
    return 0; 
} 

На данный момент этот вопрос является сделать тест и CMP имеют одинаковую стоимость? Я думаю, что да, хотя эксперты могут указывать на различия.

Практический результат: вы не должны беспокоиться об этом. Скорее всего, у вас есть способ увеличить производительность рыбы, чтобы жарить.

+2

Но шаги не совпадают. Один использует test и je, другой использует cmp и jne. Я думаю, что je и jne будут одинаковыми, но я не знаю разницы между тестом и cmp. –

+0

И я скомпилировал отладку без оптимизации. Он может отличаться при выпуске с полной оптимизацией. –

+0

Вы должны сделать две функции, которые вы вызываете из main, где происходит if, чтобы избежать каких-либо странных оптимизаций. – jmucchiello

16

Я бы ожидал, что разница будет оптимизирована любым полуподобным компилятором.

(я только что проверил с C# и скомпилированный код точно такой же, как для синтаксисов.)

+0

Они одинаковы в C#, но не на других языках. – UncleO

+3

@uncleo: Это не вопрос языка, а конкретного компилятора. – stormsoul

+2

@stormsoul: Это вопрос языка. OP не упоминает C#, и два выражения не эквивалентны в C или C++. Конечно, машинные инструкции будут отличаться на этих языках для любого компилятора. – UncleO

1

Это зависит от компилятора. Могут быть оптимизации для обоих случаев.

0

Не существует логической разницы, предполагая, что внутреннее типизирование не происходит, например, тестирование fstream.

ifstream fin; 
... 
if(! fin) 
... 
16

Я думаю, что сравнение с истинным показывает отсутствие понимания вашим партнером. Bools следует назвать вещами, чтобы избежать этого (например, isAvaliable: if (isAvailable) {...}).

2

MSVC++ 6.0 компилятор генерирует немного другой код для двух форм:

4:  if (ok) { 
00401033 mov   eax,dword ptr [ebp-8] 
00401036 and   eax,0FFh 
0040103B test  eax,eax 
0040103D je   main+36h (00401046) 
.... 
7:  if (ok == true) { 
00401046 mov   ecx,dword ptr [ebp-8] 
00401049 and   ecx,0FFh 
0040104F cmp   ecx,1 
00401052 jne   main+4Bh (0040105b) 

Прежний вариант должен быть очень немного быстрее, если я помню, мои 8086 тайминги правильно :-)

+1

Временные истины с 8086 дней, вероятно, не точны для современных процессоров. –

+0

Это оптимизированный код? Является ли «ok» логическим типом? Интересно, почему бы это не просто проверить или сравнить «байт ptr [ebp-8]» вместо того, чтобы вставить в регистр; или, протестировать или сравнить cl и/или al вместо использования поразрядных данных, а затем выполнить 32-разрядный тест или сравнить. – ChrisW

+0

Не оптимизирован. Это код на C++ и ok - это bool. –

4

Вот Python (2,6) разборка:

>>> def check(x): return (bool(x) == True) 

>>> import dis 
>>> dis.dis(check) 
    1   0 LOAD_GLOBAL    0 (bool) 
       3 LOAD_FAST    0 (x) 
       6 CALL_FUNCTION   1 
       9 LOAD_GLOBAL    1 (True) 
      12 COMPARE_OP    2 (==) 
      15 RETURN_VALUE   
>>> def check2(x): return bool(x) 

>>> dis.dis(check2) 
    1   0 LOAD_GLOBAL    0 (bool) 
       3 LOAD_FAST    0 (x) 
       6 CALL_FUNCTION   1 
       9 RETURN_VALUE   

Я полагаю, что причина check не оптимизированная из-за Python является динамическим языком. Это само по себе не означает, что Python использует плохой компилятор, но он может стоить сделать небольшой вывод типа здесь. Может быть, это имеет значение, когда создается файл .pyd?

2

Это относится к определенным языкам и тем, что они считают «правдивыми» значениями. Вот два общих: JavaScript и PHP.

Оператор triple equals на обоих этих языках гарантирует, что вы действительно проверяете логический тип истины. Например, в PHP для проверки if ($value) может отличаться от if ($value==true) или if ($value===true):

$f = true; 
$z = 1; 
$n = null; 
$a = array(1,2); 

print ($f)  ?'true':'false'; // true 
print ($f==true) ?'true':'false'; // true 
print ($f===true) ?'true':'false'; // true 
print "\n"; 
print ($z)  ?'true':'false'; // true 
print ($z==true) ?'true':'false'; // true 
print ($z===true) ?'true':'false'; // false 
print "\n"; 
print ($n)  ?'true':'false'; // false 
print ($n==true) ?'true':'false'; // false 
print ($n===true) ?'true':'false'; // false 
print "\n"; 
print ($a)  ?'true':'false'; // true 
print ($a==true) ?'true':'false'; // true 
print ($a===true) ?'true':'false'; // false 
print "\n"; 
print "\n"; 

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

+0

На самом деле в PHP оператор === гарантирует, что два значения имеют один и тот же тип. Это не имеет ничего общего с правдивостью ценности. FALSE! == 0, но если (0) оперативно идентично if (FALSE). Я уверен, что JS работает одинаково. – jmucchiello

+0

@jmucchiello Я добавил дополнение, чтобы быть более четким о том, что я имею в виду под различиями между отсутствием оператора равенства, двойными равными и тройными равными. Извините, я был неясен. – artlung

1

Тестирование на равенство true может привести к ошибке, по крайней мере, в C: in C, если «можно» использовать для целочисленных типов (не только для булевых типов) и принимать любое значение ненулевое значение; однако символ «ИСТИНА» является одним конкретным ненулевым значением (например, 1). Это может стать важным с битовыми флагами:

if (flags & DCDBIT) 
{ 
    //do something when the DCDBIT bit is set in the flags variable 
} 

Поэтому, учитывая такую ​​функцию ...

int isDcdSet() 
{ 
    return (flags & DCDBIT); 
} 

... выражение «если (isDcdSet())» не то же самое, "if (isDcdSet() == TRUE)".

В любом случае; Я думаю, что оптимизирующий компилятор должен оптимизировать любую разницу (потому что нет логической разницы), предполагая, что это язык с истинным булевым (а не целочисленным) типом.

0

Возможно, это не так, если вы работаете с nullable bool.

Пример:

Bool? myBool = true 

if(myBool) // This will not compile 

if(myBool == true) //this will compile 
+0

, потому что это не bool, это объект Nullable , который, очевидно, не является типом, который используется в инструкции if. –

10

Дубликат вопрос (Should I use `!IsGood` or `IsGood == false`?). Вот указатель на мой предыдущий ответ:

Методика тестирования специально против истинного или ложного является плохой практикой , если рассматриваемый переменное действительно предполагается использовать как логическое значение (даже если его типа не является логическим) - особенно в C/C++. Тестирование против true может (и, вероятно, будет) приводить к тонким ошибкам.

Смотрите следующий SO ответ Подробности:

Should I use `!IsGood` or `IsGood == false`?

Вот нить, которая детализирует обоснование, почему «== правда» часто ложно в более явном подробно, в том числе объяснения Страуструпа: https://qt-project.org/forums/viewthread/32642

+1

Michael: Я видел вышеупомянутый вопрос, прежде чем публиковать этот. По-моему, это не дубликат этого; лицо, задающее этот вопрос, спрашивает о том, что лучше всего на практике; Я спрашиваю конкретно, если явная проверка включает дополнительный шаг обработки без какого-либо рассмотрения того, что лучше или хуже. –

+0

В этом случае ответ на ваш вопрос для C/C++ заключается в том, что, если переменная в выражении не имеет тип bool, они * не могут * генерировать один и тот же код, потому что код семантически отличается (даже если это так немного). Однако вполне вероятно, что сгенерированный код будет в точности эквивалентен с точки зрения производительности. –

2

В синтаксисе «boolCheck == true» может быть некоторое обоснование, зависящее от имени тестируемой переменной.

Например, если имя переменной было «состояние», то вы можете иметь:

if (state) { 
    ... 
} 

или вы можете иметь

if (state == true) { 
    ... 
} 

В этом случае, я думаю, что последняя форма яснее и понятнее.

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

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

+1

Если бы я писал C#, я бы знал, что состояние должно быть логическим и, следовательно, true/false. Если бы я писал C, я понятия не имею, верно ли true в этом случае. Возможно, это означает любое определенное состояние, кроме того, что имеет значение 0, и в этом случае последняя конструкция ошибочна (и, конечно, не является улучшением). Лучше реорганизовать код, чтобы сделать его более ясным, чем введение избыточных конструкций, ИМО. – tvanfosson

+0

Согласен. Я просто пытаюсь объяснить, почему кто-то может это сделать. – skaffman

+0

+1 для заботы о том, что код говорит программистам. – ChrisW

4

По моему опыту if (flag==true) - это плохая практика.

Первый аргумент является академическим:

Если у вас есть bool flag, это либо true или false.

Теперь выражение

(flag==true) 

снова, пока true или false - это не более выразительная, только лишнее - flag не может получить «более верно» или «больше ложным», чем она уже есть. Это было бы «яснее», только если это не очевидно. flag - логическое - но есть стандартный способ исправить то, что работает для всех типов: выберите лучшее имя.

Растяжка это за причины, следующий будет «еще лучше»:

((flag==true)==true) 

Второй аргумент является прагматичным и конкретной платформы

C и ранних реализаций C++ не было никакого реального «BOOL ", поэтому существуют различные соглашения для флагов, наиболее распространенным из которых является то, что отличное от нуля истинно. Это не редкость для API, чтобы вернуть целое на основе типа BOOL, но не навязывает возвращаемое значение будет 0 или 1.

В некоторых средах используются следующие определения:

#define FALSE 0 
#define TRUE (!FALSE) 

удачи if ((1==1) == TRUE)

Кроме того, на некоторых платформах используются разные значения - например VARIANT_BOOL для VB interop - short, а VARIANT_TRUE - -1.

При смешивании библиотек, использующих эти определения, явное сравнение с истинным может быть легко замаскировано под благие намерения. Итак, не надо.

+0

Отличный ответ, у вас должно быть больше стимулов для этого;). Подумайте, что вы намеревались написать после «закрытия запятой» в конце (нет истории изменений). – Abel

+0

@Abel Спасибо :) Возможно, всего лишь часть первоначальной попытки в последнем абзаце. (прошло 7 лет, если я помню). – peterchen

0

ИМХО это плохая идея использовать if (boolCheck == true) форму, по одной простой причине: если вы случайно ввести один «равно» знак вместо двойной (т.е. if (boolCheck = true)), он назначит true к boolCheck и всегда возвращает истину , что, очевидно, было бы ошибкой. Конечно, большинство современных компиляторов покажут предупреждение, когда они видят, что (по крайней мере, компилятор C#), но многие разработчики просто игнорируют предупреждения ...

Если вы хотите быть явным, вам следует отдать предпочтение этой форме: if (true == boolCheck) , Это позволит избежать случайной привязки переменной и вызовет ошибку компиляции, если вы забудете знак «равно».

Смежные вопросы