Использование логических значений в C - PullRequest
616 голосов
/ 17 декабря 2009

C не имеет встроенных логических типов. Какой лучший способ использовать их в C?

Ответы [ 15 ]

948 голосов
/ 17 декабря 2009

От лучшего к худшему:

Вариант 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

Объяснение * * 1023 Вариант 1 будет работать, только если вы используете C99, и это "стандартный способ" сделать это. Выберите это, если это возможно. Варианты 2, 3 и 4 на практике будут иметь одинаковое поведение. # 2 и # 3 не используют #defines, что, на мой взгляд, лучше. Если вы не определились, переходите к # 1!

220 голосов
/ 18 декабря 2009

Несколько мыслей о логических значениях в C:

Я достаточно взрослый, чтобы просто использовать обычные int s в качестве моего логического типа без каких-либо определений типов, специальных определений или перечислений для значений true / false. Если вы последуете моему предложению никогда не сравнивать с булевыми константами, тогда вам все равно нужно будет использовать 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.

82 голосов
/ 17 декабря 2009

Логическим значением в C является целое число: ноль для false и ненулевое значение для true.

См. Также Логический тип данных , раздел C, C ++, Objective-C, AWK .

69 голосов
/ 15 мая 2014

Вот версия, которую я использовал:

typedef enum { false = 0, true = !false } bool;

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

Это решает проблему того, что кто-то кодирует что-то, что сводится к этому:

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. Я оставлю читателю в качестве упражнения преобразование нулевого целого числа.

43 голосов
/ 17 декабря 2009

Если вы используете компилятор C99, он имеет встроенную поддержку типов bool:

#include <stdbool.h>
int main()
{
  bool b = false;
  b = true;
}

http://en.wikipedia.org/wiki/Boolean_data_type

18 голосов
/ 18 мая 2018

обо всем по порядку. C, то есть ISO / IEC 9899 имеет логический тип в течение 19 лет, а сейчас . Это намного больше, чем ожидаемая ожидаемая продолжительность карьеры программиста на C с любительскими / академическими / профессиональными частями, объединенными при посещении этого вопроса . Моя превосходит это всего лишь на 1-2 года. Это означает, что за время , которое среднестатистический читатель вообще что-то узнал о C, C фактически имел логический тип данных .

Для типа данных #include <stdbool.h> и используйте true, false и bool. Или не включайте его и используйте вместо него _Bool, 1 и 0.


В этой ветке ответов содержатся различные опасные советы. Я обращусь к ним:

typedef int bool;
#define true 1
#define false 0

Это нет-нет, потому что случайный читатель - который изучил C в течение этих 19 лет - ожидал, что bool относится к типу данных фактический bool и будет вести себя аналогично, но это не так! Например

double a = ...;
bool b = a;

При C99 bool / _Bool значение b будет установлено на false , если a равно нулю, а true в противном случае. С typedef на месте double будет приведен к int - если значение double не находится в диапазоне для int, поведение не определено .

Естественно, то же самое относится, если true и false были объявлены в enum.

Что еще опаснее декларирует

typedef enum bool {
    false, true
} bool;

потому что теперь все значения , кроме 1 и 0, недопустимы, и если такое значение будет присвоено переменной этого типа, поведение будет полностью неопределенным .

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

  • введите int и значения 0 и 1 как есть ; и тщательно выполняйте преобразование домена из любых других значений в них с двойным отрицанием !!
  • или если вы настаиваете , вы не помните, что 0 - это ложь и ненулевое значение, по крайней мере используйте верхний регистр , чтобы они не перепутали с C99 понятия: BOOL, TRUE и FALSE!
17 голосов
/ 17 декабря 2009
typedef enum {
    false = 0,
    true
} t_bool;
11 голосов
/ 17 декабря 2009

C имеет логический тип: bool (по крайней мере, за последние 10 (!) Лет)

Включите stdbool.h и true / false будет работать как положено.

9 голосов
/ 17 декабря 2009

Все ненулевое значение оценивается как истинное в логических операциях, поэтому вы можете просто

#define TRUE 1
#define FALSE 0

и используйте константы.

1 голос
/ 16 февраля 2019

Просто дополнение к другим ответам и разъяснениям, если вам разрешено использовать 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 бит.
...