C не имеет встроенных логических типов. Какой лучший способ использовать их в C?
C не имеет встроенных логических типов. Какой лучший способ использовать их в C?
Ответы:
От лучшего к худшему:
Вариант 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!
<stdbool.h>
bool
компилятором могут быть более подходящими для предполагаемого назначения логического значения, чем использование int
(то есть компилятор может выбрать реализацию, bool
отличную от int
). Это также может привести к более строгой проверке типов во время компиляции, если вам повезет.
int
для bool
? Это расточительно. Использование unsigned char
. Или используйте встроенный Си _Bool
.
Несколько мыслей о логических значениях в 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
.
a == b
работает?
a
и считая b
с нуля, я бы рекомендовал a > 0 == b > 0
вместо этого. Если вы настаиваете на использовании правдивости произвольных ненулевых значений, !!var
выдает логическое значение 0/1, эквивалентное var
, так что вы можете написать !!a == !!b
, хотя многие читатели сочтут это запутанным.
!a == !b
также достаточно для проверки равенства, ненули становятся равными нулю, а нули равны единице.
!!a
как «преобразовать небулево a в его эквивалентное значение истинности», тогда как я бы прочитал !a
как «логически инвертировать логическую переменную a». В частности, я бы искал по какой-то конкретной причине, что логическая инверсия была желательна.
Логическое значение в 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
. Но концепция остается прежней.
[EDIT] Чтобы показать преобразование целого числа в логическое значение:
mybool somebool;
int someint = 5;
somebool = !!someint;
Первый (самый правый)! преобразует ненулевое целое число в 0, затем второе (самое левое)! преобразует 0 в myfalse
значение. Я оставлю читателю в качестве упражнения преобразование нулевого целого числа.
[РЕДАКТИРОВАТЬ] Мой стиль заключается в использовании явной установки значения в перечислении, когда требуется конкретное значение, даже если значение по умолчанию будет таким же. Пример: поскольку false должно быть равно нулю, я использую, false = 0,
а неfalse,
true
, false
и bool
выделяются в большинстве IDE, потому что они являются значениями перечислений и ЬурейеЕ, в отличие от #defines
, которые редко когда - либо подсветки синтаксиса.
gcc -ansi -pedantic -Wall
выдает предупреждений, поэтому я верю gcc
; Если это работает даже для c89
этого, должно работать на c99
aswell.
!
может только возвращать значения 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
Это нет-нет, потому что случайный читатель - который изучил C в течение этих 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) NaN не сравниваются равными 0 и, следовательно, преобразуются в 1.
При наличии на typedef
месте значение double
будет приведено к int
- если значение double не находится в диапазоне для 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 биты доступны.Вы можете использовать символ или другой контейнер с небольшим числом для него.
Псевдо-код
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
int
), поскольку на некоторых архитектурах вы получаете значительное снижение производительности от необходимости распаковывать / маскировать проверки этих переменных.
Вы можете использовать _Bool, но возвращаемое значение должно быть целым числом (1 для true, 0 для false). Тем не менее, рекомендуется включать и использовать BOOL как в C ++, как сказано в этом ответе от daniweb форума , а также этот ответ , от этого другого StackOverflow вопрос:
_Bool: логический тип C99. Использование _Bool напрямую рекомендуется только в том случае, если вы поддерживаете устаревший код, который уже определяет макросы для bool, true или false. В противном случае эти макросы стандартизированы в заголовке. Включите этот заголовок, и вы можете использовать bool, как в C ++.
Условные выражения считаются истинными, если они ненулевые, но стандарт 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, которое в любом случае может вызвать предупреждение.
Если вы используете 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))
, конечно, что дает тот же результат.