Использование логических значений в C

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

20 ответов

Решение

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

Вариант 1 (С99)

#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 будет работать, только если вы используете C99, и это "стандартный способ" сделать это. Выберите это, если это возможно.
  • Варианты 2, 3 и 4 будут иметь на практике одинаковое поведение. #2 и #3 не используют #defines, что, на мой взгляд, лучше.

Если вы не определились, идите с #1!

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

Я достаточно взрослый, чтобы просто использовать обычную ints как мой логический тип без каких-либо typedefs или специальных определений или перечислений для значений 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,

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

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

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

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

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

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

if (true == !false)

Я думаю, что мы все согласны с тем, что это не очень хорошая практика, но за единовременную стоимость выполнения "true =! False" мы устраняем эту проблему.

[РЕДАКТИРОВАТЬ] В конце концов я использовал:

typedef enum { myfalse = 0, mytrue = !myfalse } mybool;

чтобы избежать конфликта имен с другими схемами, которые определяли true а также false, Но концепция остается прежней.

[РЕДАКТИРОВАТЬ] Чтобы показать преобразование целого числа в логическое значение:

mybool somebool;
int someint = 5;
somebool = !!someint;

Первый (самый правый)! преобразует ненулевое целое число в 0, затем второе (самое левое)! преобразует 0 в myfalse значение. Я оставлю читателю в качестве упражнения преобразование нулевого целого числа.

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

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

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

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

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


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

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!
typedef enum {
    false = 0,
    true
} t_bool;

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

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

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

#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,
  • НЕ, но да, вы можете переопределить booltrue а также false но конечно не очень хорошая идея. Эта способность считается устаревшей и будет удалена в будущем.
  • Назначение скалярного типа (арифметические типы и типы указателей) _Bool или же bool, если скалярное значение равно 0 или сравнивается с 0 это будет 0в противном случае результат 1: _Bool x = 9;9 преобразуется в 1 когда назначено x,
  • _Bool 1 байт (8 бит), обычно у программиста возникает соблазн попытаться использовать другие биты, но это не рекомендуется, поскольку гарантируется только то, что для хранения данных используется только один бит, а не тип char которые имеют 8 бит доступны.

В настоящее время C99 поддерживает логические типы, но вам необходимо#include <stdbool.h>.

Пример:

#include <stdbool.h>

int main() 
{ 
    bool arr[2] = {true, false}; 

    printf("%d\n", arr[0] && arr[1]);
    printf("%d\n", arr[0] || arr[1]);

    return 0; 
} 

Выход:

0
1

@Thomas Matthews: условные выражения считаются истинными, если они ненулевые, но стандарт C требует, чтобы сами логические операторы возвращали либо 0, либо 1.

@Tom: #define TRUE! FALSE - это плохо и совершенно бессмысленно. Если заголовочный файл попадает в скомпилированный код C++, то это может привести к проблемам:

void foo(bool flag);

...

int flag = TRUE;
foo(flag);

Некоторые компиляторы генерируют предупреждение о преобразовании int => bool. Иногда люди избегают этого, делая:

foo(flag == TRUE);

заставить выражение быть C++ bool. Но если вы #define TRUE!FALSE, вы получите:

foo(flag == !0);

который в конечном итоге делает сравнение типа int-to-bool, которое в любом случае может вызвать предупреждение.

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

Псевдо-код

#define TRUE  1
#define FALSE 0

char bValue = TRUE;

Вы можете использовать _Bool, но возвращаемое значение должно быть целым числом (1 для true, 0 для false). Тем не менее, рекомендуется включать и использовать bool как в C++, как сказано в этом ответе на форуме daniweb, а также в этом ответе на этот другой вопрос stackru:

_Bool: логический тип C99. Использование _Bool напрямую рекомендуется только в том случае, если вы поддерживаете устаревший код, который уже определяет макросы для bool, true или false. В противном случае эти макросы стандартизированы в заголовке. Включите этот заголовок, и вы можете использовать bool, как в C++.

Вот это:

#define TRUE 1
#define FALSE 0

Вот что я использую:

enum {false, true};
typedef _Bool bool;

_Bool является встроенным типом в C. Он предназначен для логических значений.

Если вы используете C99, вы можете использовать _Boolтип. Нет#includes необходимы. Однако вам нужно рассматривать его как целое число, где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;

Настоящие мужчины не используют <stdbool.h>

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

Я бы использовал тест версии C, чтобы использовать встроенный логический тип C99, если он доступен, или откат к специальной реализации в противном случае.

      #include <stdint.h>
#if __STDC_VERSION__ < 199901L
#   define bool uint_fast8_t
#   define true 1
#   define false 0
#else
#   include <stdbool.h>
#endif /* __STDC_VERSION__ < 199901L */

Вы можете просто использовать директиву #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);

и так далее

Другие вопросы по тегам