C no tiene ningún tipo booleano incorporado. ¿Cuál es la mejor manera de usarlos en C?
C no tiene ningún tipo booleano incorporado. ¿Cuál es la mejor manera de usarlos en C?
Respuestas:
De mejor a peor:
Opción 1 (C99)
#include <stdbool.h>
opcion 2
typedef enum { false, true } bool;
Opción 3
typedef int bool;
enum { false, true };
Opcion 4
typedef int bool;
#define true 1
#define false 0
Si no estás decidido, ¡ve con el # 1!
<stdbool.h>
bool
el que elija el compilador pueden ser más adecuadas para el propósito previsto de un valor booleano que utilizar un int
(es decir, el compilador puede optar por implementar un valor bool
diferente a an int
). También puede resultar en una verificación de tipo más estricta en el momento de la compilación, si tiene suerte.
int
para bool
? Eso es un desperdicio. Uso unsigned char
. O use el C incorporado _Bool
.
Algunas reflexiones sobre booleanos en C:
Soy lo suficientemente mayor como para usar simplemente int
s como mi tipo booleano sin ningún tipo de definición o definición especial o enumeración para valores verdaderos / falsos. Si sigue mi sugerencia a continuación sobre nunca comparar con constantes booleanas, entonces solo necesita usar 0/1 para inicializar las banderas de todos modos. Sin embargo, este enfoque puede considerarse demasiado reaccionario en estos tiempos modernos. En ese caso, uno definitivamente debería usar<stdbool.h>
ya que al menos tiene el beneficio de estar estandarizado.
Como se llamen las constantes booleanas, úselas solo para la inicialización. Nunca escribas algo como
if (ready == TRUE) ...
while (empty == FALSE) ...
Estos siempre pueden ser reemplazados por el más claro
if (ready) ...
while (!empty) ...
Tenga en cuenta que estos pueden leerse en voz alta de manera razonable y comprensible.
Dé a sus variables booleanas nombres positivos, es decir, en full
lugar de notfull
. Este último conduce a un código que es difícil de leer fácilmente. Comparar
if (full) ...
if (!full) ...
con
if (!notfull) ...
if (notfull) ...
Ambos pares anteriores leen naturalmente, mientras que !notfull
es difícil de leer incluso como es, y empeoran mucho en expresiones booleanas más complejas.
Los argumentos booleanos generalmente deben evitarse. Considere una función definida como esta
void foo(bool option) { ... }
Dentro del cuerpo de la función, está muy claro lo que significa el argumento, ya que tiene un nombre conveniente y con suerte significativo. Pero, los sitios de llamadas se ven como
foo(TRUE);
foo(FALSE):
Aquí, es esencialmente imposible saber qué significa el parámetro sin mirar siempre la definición o declaración de la función, y empeora mucho si agrega aún más parámetros booleanos. Sugiero cualquiera
typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);
o
#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }
En cualquier caso, el sitio de la llamada ahora se ve así
foo(OPT_ON);
foo(OPT_OFF);
que el lector tiene al menos una oportunidad de entender sin desenterrar la definición de foo
.
a == b
funciona?
a
y b
contando desde cero, recomendaría en su a > 0 == b > 0
lugar. Si insiste en aprovechar la veracidad de los valores arbitrarios distintos de cero, !!var
produce el valor booleano 0/1 equivalente a var
, por lo que podría escribir !!a == !!b
, aunque bastantes lectores lo encontrarán confuso.
!a == !b
también es suficiente para probar la igualdad, los no ceros se vuelven cero y los ceros se vuelven uno.
!!a
como "convertir a no booleano a su valor de verdad equivalente", mientras que leería !a
como "invertir lógicamente la variable booleana a". En particular, buscaría alguna razón específica por la que se deseaba la inversión lógica.
Un booleano en C es un entero: cero para falso y no cero para verdadero.
Consulte también Tipo de datos booleanos , sección C, C ++, Objective-C, AWK .
Aquí está la versión que usé:
typedef enum { false = 0, true = !false } bool;
Porque falso solo tiene un valor, pero un verdadero lógico podría tener muchos valores, pero la técnica establece verdadero como lo que el compilador usará para lo contrario de falso.
Esto soluciona el problema de que alguien codifique algo que se reduciría a esto:
if (true == !false)
Creo que todos estaríamos de acuerdo en que esa no es una buena práctica, pero por el costo único de hacer "verdadero =! Falso" eliminamos ese problema.
[EDITAR] Al final usé:
typedef enum { myfalse = 0, mytrue = !myfalse } mybool;
para evitar la colisión de nombres con otros esquemas que estaban definiendo true
yfalse
. Pero el concepto sigue siendo el mismo.
[EDITAR] Para mostrar la conversión de entero a booleano:
mybool somebool;
int someint = 5;
somebool = !!someint;
El primero (más correcto)! convierte el entero distinto de cero a 0, luego el segundo (el que queda más a la izquierda). convierte el 0 en un myfalse
valor. Lo dejaré como un ejercicio para que el lector convierta un entero cero.
[EDITAR] Es mi estilo usar la configuración explícita de un valor en una enumeración cuando se requiere el valor específico, incluso si el valor predeterminado sería el mismo. Ejemplo: debido a que falso debe ser cero, lo uso en false = 0,
lugar defalse,
true
, false
y bool
se destacan en la mayoría de los IDE porque son valores de enumeración y un typedef, en oposición a #defines
, que rara vez se resaltan en la sintaxis.
gcc -ansi -pedantic -Wall
no da advertencias, así que confío gcc
; Si esto funciona incluso para c89
sí, debería funcionar c99
también para .
!
solo puede devolver valores 0
y 1
, por true = !false
lo tanto , siempre asignará el valor 1. Este método no proporciona ninguna seguridad adicional typedef enum { false, true } bool;
.
if(!value)
), pero esa excepción no es aplicable en este caso específico.
Si está utilizando un compilador C99, tiene soporte incorporado para tipos bool:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
Lo primero es lo primero. C, es decir, ISO / IEC 9899 ha tenido un tipo booleano durante 19 años . Eso es mucho más tiempo que la duración esperada de la carrera de programación en C con partes amateur / académicas / profesionales combinadas al visitar esta pregunta . La mía supera eso en solo 1-2 años. Significa que durante el tiempo en que un lector promedio ha aprendido algo acerca de C, C realmente ha tenido el tipo de datos booleano .
Para el tipo de datos, #include <stdbool.h>
y uso true
, false
y bool
. O no lo incluya, y use _Bool
, 1
y en su 0
lugar.
Hay varias prácticas peligrosas promovidas en las otras respuestas a este hilo. Me ocuparé de ellos:
typedef int bool;
#define true 1
#define false 0
Esto es no-no, porque un lector casual, que aprendió C dentro de esos 19 años, esperaría que se bool
refiera al tipo de datos real bool
y se comportaría de manera similar, ¡pero no es así! Por ejemplo
double a = ...;
bool b = a;
Con C99 bool
/ _Bool
, b
se establecería en false
iff a
era cero, y de lo true
contrario. C11 6.3.1.2p1
- Cuando se convierte cualquier valor escalar
_Bool
, el resultado es 0 si el valor se compara igual a 0; de lo contrario, el resultado es 1. 59)Notas al pie
59) Los NaN no se comparan igual a 0 y, por lo tanto, se convierten en 1.
Con el typedef
en su lugar, double
se coaccionaría a un int
- si el valor del doble no está en el rango int
, el comportamiento es indefinido .
Naturalmente, lo mismo se aplica a if true
y false
fueron declarados en unenum
.
Lo que es aún más peligroso es declarar
typedef enum bool {
false, true
} bool;
porque ahora todos los valores además de 1 y 0 no son válidos, y si dicho valor se asigna a una variable de ese tipo, el comportamiento sería completamente indefinido .
Por lo tanto, si no puede usar C99 por alguna razón inexplicable, para las variables booleanas debe usar:
int
y valores 0
y 1
tal cual ; y cuidadosamente hacer conversiones de dominio de cualquier otro valor a estos con doble negación!!
BOOL
, TRUE
y FALSE
!int
o unsigned int
para mantener una enumeración, pero no sé nada en el Estándar que pueda causar que una enumeración se comporte como algo más que un entero tipo.
typedef enum {
false = 0,
true
} t_bool;
!0 = 1
por el estándar C, y !a = 0
para cualquier valor distinto de cero de a
. El problema es que cualquier valor distinto de cero se considera verdadero. Así que si a
y b
son a la vez "verdadero", que no es necesariamente el caso de que un `== b`.
C tiene un tipo booleano: bool (al menos durante los últimos 10 (!) Años)
Incluir stdbool.h y verdadero / falso funcionará como se esperaba.
bool
ser una macro que se expanda a _Bool
. La diferencia es importante porque puede #undef
una macro (y eso está permitido, al menos como una medida de transición), pero no puede untypedef
definir un tipo. Sin embargo, no altera el objetivo principal de su primer comentario.
Todo lo que no sea cero se evalúa como verdadero en operaciones booleanas, por lo que podría simplemente
#define TRUE 1
#define FALSE 0
y usa las constantes.
Solo un complemento a otras respuestas y algunas aclaraciones, si se le permite usar 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 |
+-------+----------------+-------------------------+--------------------+
Algunas de mis preferencias:
_Bool
o bool
? Ambos están bien, pero se bool
ve mejor que la palabra clave _Bool
.bool
y _Bool
son: false
o true
. Asignar 0
o en 1
lugar de false
o true
es válido, pero es más difícil de leer y comprender el flujo lógico.Alguna información del estándar:
_Bool
NO es unsigned int
, pero es parte del grupo de tipos enteros sin signo . Es lo suficientemente grande como para contener los valores 0
o 1
.bool
true
y, false
sin duda, no es una buena idea. Esta capacidad se considera obsoleta y se eliminará en el futuro._Bool
ao bool
, si el valor escalar es igual 0
o se compara con 0
él 0
, de lo contrario el resultado es 1
: _Bool x = 9;
9
se convierte a 1
cuando se le asigna x
._Bool
es de 1 byte (8 bits), generalmente el programador está tentado a intentar usar los otros bits, pero no se recomienda, porque lo único que se garantiza es que solo se usa un bit para almacenar datos, no como el tipo char
que tiene 8 bits disponiblesPuede usar un char u otro contenedor de números pequeños para ello.
Pseudocódigo
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
int
), ya que en algunas arquitecturas se obtiene un impacto significativo en el rendimiento al tener que desempaquetar / enmascarar verificaciones en estas variables.
Puede usar _Bool, pero el valor de retorno debe ser un número entero (1 para verdadero, 0 para falso). Sin embargo, se recomienda incluir y usar bool como en C ++, como se dijo en esta respuesta del foro daniweb , así como en esta respuesta , de esta otra pregunta de stackoverflow:
_Bool: tipo booleano de C99. El uso de _Bool directamente solo se recomienda si mantiene un código heredado que ya define macros para bool, true o false. De lo contrario, esas macros están estandarizadas en el encabezado. Incluya ese encabezado y puede usar bool tal como lo haría en C ++.
Las expresiones condicionales se consideran verdaderas si no son cero, pero el estándar C requiere que los operadores lógicos devuelvan 0 o 1.
@Tom: #define TRUE! FALSE es malo y no tiene sentido. Si el archivo de encabezado se abre paso en el código C ++ compilado, puede generar problemas:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
Algunos compiladores generarán una advertencia sobre la conversión int => bool. A veces las personas evitan esto haciendo:
foo(flag == TRUE);
para forzar la expresión a ser un bool de C ++. Pero si #definas VERDADERO! FALSO, terminas con:
foo(flag == !0);
que termina haciendo una comparación int-to-bool que puede activar la advertencia de todos modos.
Si está utilizando C99, puede usar el _Bool
tipo. No #include
s son necesarios. Sin embargo, debe tratarlo como un número entero, donde 1
está true
y 0
está false
.
Luego puede definir TRUE
y 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>
y usa bool
, true
y false
como el estándar quiere que lo haga.
Esto es lo que uso:
enum {false, true};
typedef _Bool bool;
_Bool
es un tipo incorporado en C. Está destinado a valores booleanos.
Simplemente puede usar la #define
directiva de la siguiente manera:
#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;
Y use de la siguiente manera:
bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);
y así
arg
y la expresión en su conjunto: #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)
. Sin embargo, sería mejor probar la falsedad (dará la respuesta correcta incluso si arg
fue 23 en lugar de 0 o 1:. #define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)
Pero la expresión completa puede reducirse #define NOT(arg) (!(arg))
, por supuesto, a lo que produce el mismo resultado.