Відповіді:
Цей підхід використовуватиме фактичний boolean
тип (і вирішує true
та false
), якщо компілятор підтримує його. (конкретно, C ++)
Однак було б краще перевірити, чи використовується C ++ (через __cplusplus
макрос) і чи справді використовується true
і false
.
У компіляторі C це еквівалентно 0
та 1
.
(зауважте, що видалення дужок порушить це через порядок операцій)
1==1
є int
. (див. stackoverflow.com/questions/7687403/… .)
boolean
типом?
true
або false
.
#define TRUE true
і #define FALSE false
коли __cplusplus
було визначено.
Відповідь - портативність. Чисельні значення TRUE
та FALSE
не важливі. Що є важливим є те , що заява , якif (1 < 2)
має значення if (TRUE)
і заяву , як має if (1 > 2)
значення if (FALSE)
.
Зазначено, що в C (1 < 2)
оцінюється 1
і (1 > 2)
оцінюється 0
, так як, як вже говорили інші, практичної різниці щодо компілятора немає. Але дозволяючи компілятору визначити TRUE
іFALSE
відповідно до його власних правил, ви робите їх значення явними програмістам, і ви гарантуєте послідовність у вашій програмі та будь-якій іншій бібліотеці (якщо припустити, що інша бібліотека відповідає стандартам C ... ви б дивуватися).
Деяка історія
Деякі основи визначені FALSE
як 0
і TRUE
як -1
. Як і багато сучасних мов, вони інтерпретували будь-яке ненульове значення як TRUE
, але вони оцінювали булеві вирази, що були істинними як -1
. Їх NOT
функціонування було реалізовано додаванням 1 та перевертанням знаку, оскільки це було ефективно зробити так. Так 'НЕ х' став -(x+1)
. Побічним ефектом цього є те, що таке значення, як 5
оцінюється TRUE
, але NOT 5
оцінює до -6
, що також є TRUE
! Пошук такого роду помилок не є цікавим.
Найкращі практики
З огляду на фактичні правила, що нуль інтерпретується як FALSE
і будь -яке ненульове значення інтерпретується як TRUE
, ніколи не слід порівнювати булеві виразні вирази з TRUE
абоFALSE
. Приклади:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Чому? Тому що багато програмістів використовують ярлик обробки int
s якbool
s. Вони не однакові, але компілятори зазвичай це дозволяють. Так, наприклад, писати цілком законно
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Це виглядає законним, і компілятор з радістю прийме це, але, ймовірно, не робить те, що ви хотіли. Це тому , що повертається значення strcmp()
IS
0, якщо yourString == myString
<0, якщоyourString < myString
> 0, якщоyourString > myString
Отже, рядок вище повертається TRUE
лише тоді, коли yourString > myString
.
Правильний спосіб зробити це - будь-який
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
або
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
Аналогічно:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
Часто ви знайдете деякі з цих "поганих прикладів" у виробничому коді, і багато досвідчених програмістів присягаються їм: вони працюють, деякі коротші, ніж їх (педантично?) Правильні альтернативи, і ідіоми майже загальновизнані. Але врахуйте: «правильні» версії не менш ефективні, вони гарантовано портативні, вони пройдуть навіть найсуворіші вкладиші, і навіть нові програмісти їх зрозуміють.
Хіба цього не варто?
(1==1)
не більш портативний, ніж 1
. Власні правила компілятора - це мова С, що чітко і однозначно стосується семантики операторів рівності та реляції. Я ніколи не бачив, як компілятор помилявся з цим матеріалом.
strcmp
як відомо, є меншим, рівним або більшим, ніж 0. Це не гарантовано, що буде -1, 0 або 1, і в дикій природі є платформи, які не повертають ці значення, щоб отримати швидкість реалізації. Отже, якщо strcmp(a, b) == TRUE
тоді, a > b
але зворотне значення не може мати значення.
(1==1)
і 1
обидва є постійними виразами типу int
зі значенням 1. Вони семантично однакові. Я думаю, ви можете написати код, який задовольняє читачів, які цього не знають, але де це закінчується?
(1 == 1)
Трюк корисний для визначенняTRUE
таким чином , що є прозорим для C, але забезпечує краще набравши в C ++. Цей же код можна інтерпретувати як C або C ++, якщо ви пишете на діалекті під назвою "Очистити C" (який компілюється як C або C ++) або якщо ви пишете файли заголовків API, які можуть бути використані програмістами C або C ++.
У одиницях перекладу С 1 == 1
має точно таке значення, як і 1
; і 1 == 0
має те саме значення, що і 0
. Однак у підрозділах перекладу С ++ 1 == 1
є тип bool
. Отже, TRUE
визначений таким чином макрос краще інтегрується в C ++.
Прикладом того, як вона краще інтегрується, є те, що, наприклад, якщо функція foo
має перевантаження для int
і для bool
, тоді foo(TRUE)
вибере bool
перевантаження. Якщо TRUE
це просто визначено як 1
, він не працюватиме добре на C ++. foo(TRUE)
захочеint
перевантаження.
Звичайно, C99 представив bool
, true
і, false
і це можна використовувати у файлах заголовків, які працюють з C99 і з C.
Однак:
TRUE
та FALSE
як (0==0)
і (1==0)
передує С99.Якщо ви працюєте в змішаному C і C ++ проект, і не хочете , C99, визначає нижній регістр true
, false
а bool
замість цього.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Коли це було сказано, цю 0==0
хитрість (програвач) використовували деякі програмісти навіть у коді, який ніколи не мав на меті взаємодіяти з C ++. Це нічого не купує і говорить про те, що програміст має нерозуміння того, як булеві працюють у C.
Якщо пояснення C ++ не було зрозумілим, ось тестова програма:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
Вихід:
bool
int
Щодо питання з коментарів про те, як перевантажені функції C ++, що стосуються змішаного програмування на C та C ++. Вони просто ілюструють різницю типів. Важливою причиною того, що потрібно, щоб true
константа була bool
складена як C ++, - чиста діагностика. На найвищих рівнях попередження компілятор C ++ може попередити нас про перетворення, якщо ми передамо ціле число в якості bool
параметра. Однією з причин написання в Clean C є не тільки те, що наш код є більш портативним (оскільки його розуміють компілятори C ++, не лише компілятори C), але ми можемо отримати користь від діагностичних думок компіляторів C ++.
TRUE
будуть відрізнятися під C ++.
#ifdef __cplusplus
для вираження свого наміру набагато чіткіше.
bool
і int
не мають великого значення на практиці, оскільки вони неявно конвертуються один в одного (а в С насправді "однакові" , зверніть увагу на цитати , хоча) і не так багато ситуацій, в яких вам дійсно потрібно роз'єднати між собою. "не так багато", ймовірно, було занадто важким, "набагато менше порівняно з кодом із використанням шаблонів і перевантаження", можливо, було б краще
#define TRUE (1==1)
#define FALSE (!TRUE)
еквівалентно
#define TRUE 1
#define FALSE 0
в С.
Результатом роботи реляційних операторів є 0
або 1
. 1==1
гарантовано оцінюється 1
і !(1==1)
гарантовано оцінюється 0
.
Абсолютно немає підстав використовувати першу форму. Зауважимо, що перша форма є не менш ефективною, оскільки майже для всіх компіляторів константний вираз оцінюється під час компіляції, а не під час виконання. Це дозволено відповідно до цього правила:
(C99, 6.6p2) "Постійний вираз можна оцінювати під час перекладу, а не під час виконання, і відповідно може використовуватися в будь-якому місці, де може бути константа."
PC-Lint навіть видасть повідомлення (506, бульне значення постійного значення), якщо ви не використовуєте літерал для TRUE
та FALSE
макросів:
Для C,
TRUE
слід визначити, що бути1
. Однак інші мови використовують інші кількості, ніж 1, тому деякі програмісти вважають, що!0
це безпечно.
Також у C99, stdbool.h
визначення булевих макросів true
та false
прямо використовуваних літералів:
#define true 1
#define false 0
1==1
гарантовано буде оцінено до1
if(foo == true)
, який буде переходити від просто поганої практики до відвертої баггі.
(x == TRUE)
може мати інше значення істини, ніж x
.
Крім C ++ (вже згадуваного), ще одна перевага - це інструменти статичного аналізу. Компілятор позбавить від будь-якої неефективності, але статичний аналізатор може використовувати власні абстрактні типи для розмежування результатів порівняння та інших цілих типів, тому він неявно знає, що TRUE повинен бути результатом порівняння і не слід вважати сумісним з цілим числом.
Очевидно, C говорить, що вони сумісні, але ви можете заборонити навмисне використання цієї функції, щоб допомогти виділити помилки - наприклад, де хтось може заплутатися &
і &&
чи переплутав їх пріоритет оператора.
if (boolean_var == TRUE)
за допомогою розширення, до if (boolean_var == (1 == 1))
якого завдяки розширеному типу інформації (1 == 1)
вузол потрапляє в шаблон if (<*> == <boolean_expr>)
.
Пратична різниця - жодна. 0
оцінюється false
і 1
оцінюється до true
. Той факт, що ви використовуєте булевий вираз ( 1 == 1
) або 1
, щоб визначити true
, не має ніякого значення. Вони обидва оцінюються int
.
Зверніть увагу , що стандартна бібліотека C надає спеціальний заголовок для визначення булевих: stdbool.h
.
true
оцінюється 1
і false
оцінюється до 0
. C не знає про рідні булеві типи, вони просто ints.
int
, зі значенням 0
або 1
. C має фактичний булевий тип ( _Bool
з макросом, bool
визначеним у <stdbool.h>
, але це було додано лише у C99, що не змінило семантику операторів для використання нового типу.
_Bool
і <stdbool.h>
є #define bool _Bool
.
1 == 1
оцінюють як int
. Відредаговано.
Ми не знаємо точного значення, якому TRUE дорівнює, і компілятори можуть мати свої власні визначення. Отже, те, що ти приводиш, - це використовувати внутрішній компілятор для визначення. Це не завжди потрібно, якщо у вас є хороші звички програмування, але ви можете уникнути проблем із поганим стилем кодування, наприклад:
якщо ((a> b) == ІСТИНА)
Це може бути катастрофою, якщо вручну визначити TRUE як 1, тоді як внутрішнє значення TRUE - інше.
>
оператор завжди дає 1 для true, 0 для false. Немає можливості жодного компілятора C зрозуміти це неправильно. Порівняння рівності TRUE
та FALSE
поганий стиль; вище сказане більш чітко записано як if (a > b)
. Але думка про те, що різні компілятори C можуть по-різному ставитися до істини та неправди, просто неправильна.
Зазвичай в мові програмування на C 1 визначається як істинне, а 0 - як хибне. Отже, чому ви бачите таке досить часто:
#define TRUE 1
#define FALSE 0
Однак будь-яке число, яке не дорівнює 0, буде оцінено істинним, як і в умовному твердженні. Тому, використовуючи наведене нижче:
#define TRUE (1==1)
#define FALSE (!TRUE)
Можна просто явно показати, що ви намагаєтеся захистити його безпечно, зробивши помилкою рівну тому, що не відповідає дійсності.
#define TRUE (’/’/’/’)
:;#define FALSE (’-’-’-’)
(взято з coding-guidelines.com/cbook/cbook1_1.pdf сторінка 871)