He visto definiciones en C
#define TRUE (1==1)
#define FALSE (!TRUE)
¿Es esto necesario? ¿Cuál es el beneficio sobre simplemente definir VERDADERO como 1 y FALSO como 0?
He visto definiciones en C
#define TRUE (1==1)
#define FALSE (!TRUE)
¿Es esto necesario? ¿Cuál es el beneficio sobre simplemente definir VERDADERO como 1 y FALSO como 0?
Respuestas:
Este enfoque utilizará el boolean
tipo real (y resolverá true
y false
) si el compilador lo admite. (específicamente, C ++)
Sin embargo, sería mejor verificar si C ++ está en uso (a través de la __cplusplus
macro) y realmente usar true
y false
.
En un compilador de C, esto es equivalente a 0
y 1
.
(tenga en cuenta que eliminar los paréntesis lo romperá debido al orden de las operaciones)
1==1
es un int
. (ver stackoverflow.com/questions/7687403/… .)
boolean
tipo?
true
o false
.
#define TRUE true
y #define FALSE false
siempre que __cplusplus
esté definido.
La respuesta es la portabilidad. Los valores numéricos de TRUE
y FALSE
no son importantes. Lo que es importante es que una afirmación como if (1 < 2)
se evalúa en if (TRUE)
y una declaración como if (1 > 2)
evalúa a if (FALSE)
.
Por supuesto, en C, (1 < 2)
evalúa 1
y (1 > 2)
evalúa a 0
, por lo que, como han dicho otros, no hay una diferencia práctica en lo que respecta al compilador. Pero al permitir que el compilador defina TRUE
y de FALSE
acuerdo con sus propias reglas, está haciendo que sus significados sean explícitos para los programadores, y está garantizando la coherencia dentro de su programa y cualquier otra biblioteca (suponiendo que la otra biblioteca siga los estándares C ... estar asombrado).
Alguna historia
Algunos BASICs definidos FALSE
como 0
y TRUE
como -1
. Al igual que muchos lenguajes modernos, interpretaron cualquier valor distinto de cero como TRUE
, pero evaluaron expresiones booleanas que eran verdaderas como -1
. Su NOT
operación se implementó agregando 1 y volteando el signo, porque era eficiente hacerlo de esa manera. Entonces se convirtió en 'NO x' -(x+1)
. Un efecto secundario de esto es que un valor como 5
evalúa a TRUE
, pero NOT 5
evalúa a -6
, ¡que también lo es TRUE
! Encontrar este tipo de error no es divertido.
Mejores prácticas
Dadas las de facto reglas que cero se interpreta como FALSE
y cualquier valor distinto de cero se interpreta como TRUE
, usted debe nunca se comparen las expresiones booleanas de aspecto a TRUE
oFALSE
. Ejemplos:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
¿Por qué? Porque muchos programadores usan el atajo de tratar int
s como bool
s. No son lo mismo, pero los compiladores generalmente lo permiten. Entonces, por ejemplo, es perfectamente legal escribir
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Eso parece legítimo, y el compilador lo aceptará felizmente, pero probablemente no haga lo que quieras. Eso es porque el valor de retorno de strcmp()
es
0 si yourString == myString
<0 si yourString < myString
> 0 siyourString > myString
Entonces la línea de arriba TRUE
solo regresa cuando yourString > myString
.
La forma correcta de hacer esto es
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
o
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
Similar:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
A menudo encontrará algunos de estos "malos ejemplos" en el código de producción, y muchos programadores experimentados juran por ellos: funcionan, algunos son más cortos que sus alternativas correctas (¿pedante?) Y los modismos son casi universalmente reconocidos. Pero considere: las versiones "correctas" no son menos eficientes, están garantizadas para ser portátiles, pasarán incluso las cartas más estrictas e incluso los nuevos programadores las entenderán.
¿No vale eso?
(1==1)
No es más portátil que 1
. Las propias reglas del compilador son las del lenguaje C, que es claro e inequívoco sobre la semántica de la igualdad y los operadores relacionales. Nunca he visto a un compilador interpretar mal estas cosas.
strcmp
se sabe que el valor devuelto por es menor, igual o mayor que 0. No se garantiza que sea -1, 0 o 1 y hay plataformas en la naturaleza que no devuelven esos valores para ganar velocidad de implementación. Entonces, si es strcmp(a, b) == TRUE
así, a > b
pero la implicación inversa podría no ser válida.
(1==1)
y 1
ambas son expresiones constantes de tipo int
con el valor 1. Son semánticamente idénticas. Supongo que puedes escribir código que se dirija a lectores que no lo saben, pero ¿dónde termina?
El (1 == 1)
truco es útil para definir TRUE
de una manera que sea transparente para C, pero que proporcione una mejor escritura en C ++. El mismo código puede interpretarse como C o C ++ si está escribiendo en un dialecto llamado "Clean C" (que se compila como C o C ++) o si está escribiendo archivos de encabezado de API que pueden ser utilizados por programadores de C o C ++.
En las unidades de traducción C, 1 == 1
tiene exactamente el mismo significado que 1
; y 1 == 0
tiene el mismo significado que 0
. Sin embargo, en las unidades de traducción de C ++, 1 == 1
tiene tipo bool
. Entonces la TRUE
macro definida de esa manera se integra mejor en C ++.
Un ejemplo de cómo se integra mejor es que, por ejemplo, si la función foo
tiene sobrecargas por int
y para bool
, entonces foo(TRUE)
elegirá la bool
sobrecarga. Si TRUE
solo se define como 1
, entonces no funcionará bien en C ++. foo(TRUE)
querrá la int
sobrecarga.
Por supuesto, C99 introdujo bool
, true
y false
y estos se pueden utilizar en los archivos de cabecera que trabajan con C99 y con C.
Sin embargo:
TRUE
y FALSE
como (0==0)
y (1==0)
predates C99.Si está trabajando en un proyecto de C mixta y C ++, y no desea C99, definir el menor de los casos true
, false
y bool
en su lugar.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Dicho esto, el 0==0
truco fue (¿es?) Utilizado por algunos programadores incluso en código que nunca tuvo la intención de interactuar con C ++ de ninguna manera. Eso no compra nada y sugiere que el programador tiene un malentendido sobre cómo funcionan los booleanos en C.
En caso de que la explicación de C ++ no fuera clara, aquí hay un programa de prueba:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
La salida:
bool
int
En cuanto a la pregunta de los comentarios sobre cómo se sobrecargan las funciones de C ++ relevantes para la programación mixta de C y C ++. Estos solo ilustran una diferencia de tipo. Una razón válida para querer una true
constante bool
cuando se compila como C ++ es para un diagnóstico limpio. En sus niveles de advertencia más altos, un compilador de C ++ podría advertirnos sobre una conversión si pasamos un entero como bool
parámetro. Una razón para escribir en Clean C no es solo que nuestro código es más portátil (ya que los compiladores de C ++ lo entienden, no solo los compiladores de C), sino que podemos beneficiarnos de las opiniones de diagnóstico de los compiladores de C ++.
TRUE
diferirán en C ++.
#ifdef __cplusplus
para expresar su intención con mucha más claridad.
bool
y int
no importan mucho en la práctica, ya que son implícitamente convertibles entre sí (y en C en realidad "lo mismo" , tenga en cuenta las citas , sin embargo) y no hay muchas situaciones en las que realmente necesite desambiguar entre los dos. "no mucho" probablemente era demasiado pesado, "mucho menos en comparación con el código que usa plantillas y sobrecarga" quizás hubiera sido mejor.
#define TRUE (1==1)
#define FALSE (!TRUE)
es equivalente a
#define TRUE 1
#define FALSE 0
C ª.
El resultado de los operadores relacionales es 0
o 1
. 1==1
está garantizado para ser evaluado 1
y !(1==1)
está garantizado para ser evaluado 0
.
No hay absolutamente ninguna razón para usar la primera forma. Sin embargo, tenga en cuenta que la primera forma no es menos eficiente, ya que en casi todos los compiladores se evalúa una expresión constante en tiempo de compilación en lugar de en tiempo de ejecución. Esto está permitido de acuerdo con esta regla:
(C99, 6.6p2) "Se puede evaluar una expresión constante durante la traducción en lugar del tiempo de ejecución, y en consecuencia se puede usar en cualquier lugar que pueda ser una constante".
PC-Lint incluso emitirá un mensaje (506, valor booleano constante) si no utiliza un literal para TRUE
y FALSE
macros:
Para C,
TRUE
debe definirse como ser1
. Sin embargo, otros idiomas usan cantidades distintas de 1, por lo que algunos programadores sienten que!0
está jugando de forma segura.
También en C99, las stdbool.h
definiciones de macros booleanas true
y false
directamente usan literales:
#define true 1
#define false 0
1==1
está garantizado para ser evaluado a1
if(foo == true)
, que pasará de ser simplemente una mala práctica a un buggy plano.
(x == TRUE)
puede tener un valor de verdad diferente que x
.
Aparte de C ++ (ya mencionado), otro beneficio es para las herramientas de análisis estático. El compilador eliminará cualquier ineficiencia, pero un analizador estático puede usar sus propios tipos abstractos para distinguir entre resultados de comparación y otros tipos enteros, por lo que sabe implícitamente que VERDADERO debe ser el resultado de una comparación y no debe suponerse que es compatible. con un entero
Obviamente, C dice que son compatibles, pero puede optar por prohibir el uso deliberado de esa función para ayudar a resaltar errores, por ejemplo, dónde alguien podría haber confundido &
y &&
/ o haber confundido su precedencia de operador.
if (boolean_var == TRUE)
través de una expansión a la if (boolean_var == (1 == 1))
cual, gracias a la información de tipo mejorada del (1 == 1)
nodo, se incluye en el patrón if (<*> == <boolean_expr>)
.
La diferencia práctica es ninguna. 0
se evalúa false
y 1
se evalúa en true
. El hecho de que use una expresión booleana ( 1 == 1
) o 1
, para definir true
, no hace ninguna diferencia. Ambos son evaluados para int
.
Tenga en cuenta que la biblioteca estándar de C proporciona una cabecera específica para definir booleanos: stdbool.h
.
true
se evalúa 1
y false
se evalúa en 0
. C no sabe acerca de los tipos booleanos nativos, son solo ints.
int
, con valor 0
o 1
. C tiene un tipo booleano real ( _Bool
con una macro bool
definida en <stdbool.h>
, pero eso solo se agregó en C99, lo que no cambió la semántica de los operadores para usar el nuevo tipo.
_Bool
y <stdbool.h>
tiene #define bool _Bool
.
1 == 1
evaluación como int
. Editado
No sabemos el valor exacto al que TRUE es igual y los compiladores pueden tener sus propias definiciones. Entonces, lo que usted privilegia es usar el interno del compilador para la definición. Esto no siempre es necesario si tiene buenos hábitos de programación, pero puede evitar problemas con algún estilo de codificación incorrecto, por ejemplo:
if ((a> b) == TRUE)
Esto podría ser un desastre si define manualmente VERDADERO como 1, mientras que el valor interno de VERDADERO es otro.
>
operador siempre produce 1 para verdadero, 0 para falso. No hay posibilidad de que ningún compilador de C se equivoque. Las comparaciones de igualdad con TRUE
y FALSE
son de mal estilo; lo anterior se escribe más claramente como if (a > b)
. Pero la idea de que diferentes compiladores de C pueden tratar la verdad y lo falso de manera diferente es simplemente incorrecta.
Por lo general, en el lenguaje de programación C, 1 se define como verdadero y 0 se define como falso. De ahí por qué ves lo siguiente con bastante frecuencia:
#define TRUE 1
#define FALSE 0
Sin embargo, cualquier número que no sea igual a 0 también se evaluaría como verdadero en una declaración condicional. Por lo tanto, usando lo siguiente:
#define TRUE (1==1)
#define FALSE (!TRUE)
Puede demostrar explícitamente que está tratando de ir a lo seguro haciendo falso igual a lo que no es cierto.
#define TRUE (’/’/’/’)
;#define FALSE (’-’-’-’)
(tomado de coding-guidelines.com/cbook/cbook1_1.pdf página 871)