C не має вбудованих булевих типів. Який найкращий спосіб використовувати їх у С?
C не має вбудованих булевих типів. Який найкращий спосіб використовувати їх у С?
Відповіді:
Від кращого до гіршого:
Варіант 1 (C99)
#include <stdbool.h>
Варіант 2
typedef enum { false, true } bool;
Варіант 3
typedef int bool;
enum { false, true };
Варіант 4
typedef int bool;
#define true 1
#define false 0
Якщо ви не визначилися, ідіть з №1!
<stdbool.h> boolкомпілятора можуть бути більш підходящими за цільовим призначенням булевого значення, ніж використання int(тобто компілятор може вирішити реалізувати boolінакше, ніж an int). Це також може призвести до більш жорсткої перевірки типу під час компіляції, якщо вам пощастить.
intдля bool? Це марно. Використовуйте unsigned char. Або використовувати вбудовану команду мови C _Bool.
Кілька думок про булеви в C:
Я досить старий, що я просто використовую звичайний ints як мій булевський тип без будь-яких typedefів або спеціальних визначень чи перерахунків для правдивих / хибних значень. Якщо ви дотримуєтесь моєї пропозиції нижче щодо того, щоб ніколи не порівнювати з булевими константами, то вам потрібно лише використовувати 0/1 для ініціалізації прапорів. Однак такий підхід може вважатися надто реакційним у ці сучасні часи. У цьому випадку, безумовно, слід використовувати, <stdbool.h>оскільки це принаймні має перевагу стандартизації.
Як би не називали булеві константи, використовуйте їх лише для ініціалізації. Ніколи не писати щось подібне
if (ready == TRUE) ...
while (empty == FALSE) ...
Їх завжди можна замінити яснішими
if (ready) ...
while (!empty) ...
Зауважте, що їх можна насправді розумно і зрозуміло читати вголос.
Дайте своїм булевим змінним позитивні назви, тобто fullзамість notfull. Останнє призводить до коду, який важко легко прочитати. Порівняйте
if (full) ...
if (!full) ...
з
if (!notfull) ...
if (notfull) ...
Обидві колишньої пари читають природно, тоді !notfullяк незручно читати, як це є, і стає набагато гірше у складніших булевих виразах.
Булові аргументи, як правило, слід уникати. Розглянемо функцію, визначену так
void foo(bool option) { ... }
У тій частині функції дуже ясно, що означає аргумент, оскільки він має зручне і, сподіваємось, значуще ім'я. Але, схожі сайти викликів
foo(TRUE);
foo(FALSE):
Тут, по суті, неможливо сказати, що означав параметр, не дивлячись завжди на визначення функції або декларацію, і це стає набагато гіршим, як тільки ви додасте ще більш булеві параметри. Я пропоную будь-яке
typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);
або
#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }
У будь-якому випадку сайт виклику зараз виглядає так
foo(OPT_ON);
foo(OPT_OFF);
що читач має принаймні шанс зрозуміти, не дратуючи визначення foo.
a == bпрацює?
aі bпідраховувати від нуля, я б рекомендував a > 0 == b > 0замість цього. Якщо ви наполягаєте на тому, щоб скористатися правдивістю довільних ненульових значень, ви отримаєте !!varбулеве значення 0/1, еквівалентне тому var, щоб ви могли написати !!a == !!b, хоча досить багато читачів вважають це заплутаним.
!a == !bтакож достатньо для перевірки рівності, ненулі стають нульовими, а нулі - цілими.
!!aяк "конвертувати небулевий a в його еквівалентне значення істини", тоді як я читав би !aяк "логічно інвертувати булева змінна a". Зокрема, я хотів би шукати якусь конкретну причину, якою хотілося логічної інверсії.
Булеве значення в C - це ціле число: нуль для помилкового і не нульове значення для істинного.
Дивіться також логічний тип даних , розділ C, C ++, Objective-C, AWK .
Ось версія, яку я використав:
typedef enum { false = 0, true = !false } bool;
Оскільки false має лише одне значення, але логічна правда може мати багато значень, але техніка встановлює true таким, що компілятор буде використовувати для протилежного false.
Це вирішує проблему, коли хтось кодує щось, що зводиться до цього:
if (true == !false)
Я думаю, що ми всі погодимось з тим, що це не є хорошою практикою, але за разову вартість виконання "true =! False" ми усуваємо цю проблему.
[EDIT] Зрештою, я використав:
typedef enum { myfalse = 0, mytrue = !myfalse } mybool;
щоб уникнути зіткнення імен з іншими схемами, які визначали trueі false. Але концепція залишається такою ж.
[EDIT] Щоб показати перетворення цілого числа в булеве:
mybool somebool;
int someint = 5;
somebool = !!someint;
Перший (найправильніше)! перетворює ненульове ціле число в 0, потім друге (найбільше ліворуч)! перетворює 0 у myfalseзначення. Я залишу це як вправу для читача для перетворення нульового цілого числа.
[EDIT] У моєму стилі використовувати явне встановлення значення в enum, коли потрібне конкретне значення, навіть якщо значення за замовчуванням було б однаковим. Приклад: Тому що помилковим потрібно нуль, я використовую, false = 0,а неfalse,
true, falseі boolвиділяються в більшості IDE, тому що вони є значеннями перерахувань і ЬурейеЕ, на відміну від #defines, які рідко коли - або підсвічування синтаксису.
gcc -ansi -pedantic -Wallне дає попереджень, тому я довіряю gcc; Якщо це працює навіть для c89цього, він повинен працювати c99також.
!може повертати лише значення 0і 1, таким чином true = !false, завжди призначатиме значення 1. Цей метод не забезпечує додаткової безпеки typedef enum { false, true } bool;.
if(!value)), але цей виняток не застосовується в цьому конкретному випадку.
Якщо ви використовуєте компілятор C99, він має вбудовану підтримку типів bool:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
Насамперед. C, тобто ISO / IEC 9899, має булевий тип вже 19 років . Це набагато довший час, ніж очікувана тривалість кар'єри програмування на С, з поєднанням аматорських / академічних / професійних під час відвідування цього питання . Шахта перевершує це, можливо, лише на 1-2 роки. Це означає, що за час , коли пересічний читач взагалі що-небудь дізнався про C, C насправді мав бульний тип даних .
Для типу даних, #include <stdbool.h>і використання true, falseі bool. Або не включайте його, а використовуйте _Bool, 1а 0замість цього.
В інших відповідях на цю тему пропонуються різні небезпечні практики. Я звернусь до них:
typedef int bool;
#define true 1
#define false 0
Це ні-ні, тому що випадковий читач - який навчився С протягом цих 19 років - очікував, що це boolстосується фактичного bool типу даних і поводитиметься аналогічно, але це не так! Наприклад
double a = ...;
bool b = a;
З C99 bool/ _Bool, bбуде встановлений false тоді і тільки тоді a дорівнював нулю, а в trueіншому випадку. C11 6.3.1.2p1
- Коли будь-яке скалярне значення перетворюється на
_Bool, результат дорівнює 0, якщо значення порівнюється рівним 0; в іншому випадку результат 1. 59)Виноски
59) NaNs не порівнюються рівними 0 і, таким чином, перетворюються на 1.
Якщо на typedefмісці, значення doubleбуде примусово до int- якщо значення подвійного не знаходиться в діапазоні для int, поведінка не визначена .
Природно, те саме стосується, якщо trueі falseбули оголошені в enum.
Що ще небезпечніше - це декларування
typedef enum bool {
false, true
} bool;
оскільки тепер усі значення, окрім 1 та 0, є недійсними, і якщо таке значення буде присвоєно змінній цього типу, поведінка буде повністю визначеною .
Отже, якщо ви не можете використовувати C99 з якихось незрозумілих причин, для булевих змінних слід використовувати:
intі значення 0та 1 як є ; і обережно робіть перетворення домену з будь-яких інших значень до них із подвійним запереченням!!BOOL, TRUEі FALSE!intабо unsigned intдля проведення перерахунку, але я не знаю нічого у Стандарті, яке б спричиняло поведінку перерахунку як будь-що, крім цілого числа тип.
typedef enum {
false = 0,
true
} t_bool;
!0 = 1за стандартом C і !a = 0для будь-якого ненульового значення a. Проблема полягає в тому, що будь-який ненульовий вважається істинним. Тож якщо aі bобидва є "правдивими", це не обов'язково, що `a == b`.
C має булевий тип: bool (принаймні за останні 10 (!) Років)
Включити stdbool.h та true / false буде працювати, як очікувалося.
boolповинен бути макросом, який розширюється до _Bool. Різниця має значення тому, що ви можете #undefмакрос (і це дозволено, принаймні як перехідний захід), але ви не untypedefможете вводити typedef. Однак це не змінює основного погляду вашого першого коментаря.
Будь-яке ненульове значення в булевих операціях оцінюється справжнім, тому ви могли просто
#define TRUE 1
#define FALSE 0
і використовувати константи.
Просто доповнення до інших відповідей та деяким уточненням, якщо вам дозволяється використовувати C99.
+-------+----------------+-------------------------+--------------------+
| Name | Characteristic | Dependence in stdbool.h | Value |
+-------+----------------+-------------------------+--------------------+
| _Bool | Native type | Don't need header | |
+-------+----------------+-------------------------+--------------------+
| bool | Macro | Yes | Translate to _Bool |
+-------+----------------+-------------------------+--------------------+
| true | Macro | Yes | Translate to 1 |
+-------+----------------+-------------------------+--------------------+
| false | Macro | Yes | Translate to 0 |
+-------+----------------+-------------------------+--------------------+
Деякі з моїх переваг:
_Boolабо bool? І те, і інше добре, але boolвиглядає краще, ніж ключове слово _Bool.boolта _Boolє: falseабо true. Призначення 0або 1замість falseабо trueє дійсним, але важче читати та розуміти логічний потік.Деякі відомості зі стандарту:
_BoolНЕ unsigned int, але є частиною цілочислових непідписаних типів групи . Він досить великий, щоб утримувати значення 0або 1.bool trueі , falseале впевнений , що це не дуже гарна ідея. Ця здатність вважається застарілою і надалі буде видалена._Boolабо bool, якщо скалярне значення дорівнює 0або порівнюватиметься з 0ним 0, в іншому випадку результат 1: _Bool x = 9; 9перетворюється на, 1коли присвоюється x._Boolє 1 байт (8 біт), зазвичай програміст спокушається спробувати використати інші біти, але це не рекомендується, оскільки єдине гарантоване, що надається, - це лише один біт для зберігання даних, а не типу, у charякого є 8 доступні біти.Ви можете використовувати char або інший контейнер з невеликою кількістю.
Псевдокод
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
int), оскільки в деяких архітектурах ви отримуєте значне враження від продуктивності від розпакування / маскування перевірок цих змінних.
Ви можете використовувати _Bool, але значення повернення повинно бути цілим числом (1 для істинного, 0 для помилкового). Однак, рекомендується включати і використовувати bool, як у C ++, як сказано у цій відповіді з форуму daniweb , а також у цій відповіді з цього іншого запитання про stackoverflow:
_Bool: бульовий тип C99. Використовувати _Bool безпосередньо рекомендується лише в тому випадку, якщо ви підтримуєте застарілий код, який вже визначає макроси для bool, true або false. В іншому випадку ці макроси стандартизовані в заголовку. Включіть цей заголовок, і ви можете використовувати bool так само, як і в C ++.
Умовні вирази вважаються істинними, якщо вони не нульові, але стандарт C вимагає, щоб логічні оператори самі повертали 0 або 1.
@Tom: #define ПРАВДА! БУДЬ погано і абсолютно безглуздо. Якщо файл заголовка пробивається в компільований код C ++, це може призвести до проблем:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
Деякі компілятори генерують попередження про перетворення int => bool. Іноді люди уникають цього, роблячи:
foo(flag == TRUE);
змусити вираз бути C ++ bool. Але якщо ви #define ПРАВИЛЬНО! ФАЛЬСЕ, ви закінчите:
foo(flag == !0);
що в кінцевому підсумку робить внутрішнє порівняння порівняння, яке в будь-якому випадку може викликати попередження.
Якщо ви використовуєте C99, ви можете використовувати _Boolтип. Ні #includeз яких не потрібно. Потрібно ставитися до цього як до цілого числа, хоча там, де 1є trueі 0є false.
Потім можна визначити TRUEі FALSE.
_Bool this_is_a_Boolean_var = 1;
//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;
#include <stdbool.h>і використовувати bool, trueі, falseяк стандарт, який ви хочете, щоб ви.
Це те, що я використовую:
enum {false, true};
typedef _Bool bool;
_Bool це вбудований тип у C. Він призначений для булевих значень.
Ви можете просто використовувати #defineдирективу так:
#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;
І використовувати наступним чином:
bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);
і так далі
argі вираз в цілому: #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE). Однак було б краще перевірити на хибність (це дасть правильну відповідь, навіть якщо argбуло 23 замість 0 або 1: #define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)Але весь вираз можна звести #define NOT(arg) (!(arg)), звичайно, що дає такий же результат.