it-swarm.com.ru

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

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

615
neuromancer

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

Вариант 1 (C99)

#include <stdbool.h>

Вариант 2

typedef enum { false, true } bool;

Вариант

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!

945
Thomas Bonini

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

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

218
Dale Hagglund

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

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

80
Fortega

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

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

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

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

if (true == !false)

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

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

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

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

[EDIT] Чтобы показать преобразование целого числа в логическое значение:

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

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

69
Michael Potter

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

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

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

43
Gary Willoughby
typedef enum {
    false = 0,
    true
} t_bool;
17
mouviciel

Обо всем по порядку. 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 в противном случае. При наличии typedefdouble будет приведено к int - если значение типа double не находится в диапазоне для int, поведение не определено .

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

Что еще более опасно объявляет

typedef enum bool {
    false, true
} bool;

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

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

  • введите int и значения 0 и 1 как есть ; и тщательно выполняйте преобразования доменов из любых других значений в них с двойным отрицанием !!
  • или если вы настаиваете , то вы не помните, что 0 - это ложь и ненулевое значение, по крайней мере используйте регистр , чтобы они не путались с концепциями C99: BOOL, TRUE и FALSE!
17
Antti Haapala

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

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

11
dmeister

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

#define TRUE 1
#define FALSE 0

и использовать константы.

9
ggambett

@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, которое может в любом случае вызвать предупреждение.

1
jamesdlin

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

псевдо-код

#define TRUE  1
#define FALSE 0

char bValue = TRUE;
0
Filip Ekberg

Вот это:

#define TRUE 1
#define FALSE 0
0
RngTng

Просто дополнение к другим ответам и некоторым разъяснениям, если вам разрешено использовать 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, в противном случае результат is 1: _Bool x = 9;9 преобразуется в 1 при назначении x.
  • _Bool составляет 1 байт (8 бит), обычно программист испытывает искушение попытаться использовать другие биты, но это не рекомендуется, потому что дается только один гарантированный, что для хранения данных используется только один бит, а не тип char, который есть 8 бит доступны.
0
Undefined Behavior

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

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

0
Lokian