#define TRUE! FALSE vs #define TRUE 1

Dejando de lado el hecho de que desde c99 ha existido stdbool.h , al definir macros para manejar tipos booleanos en C ¿hay alguna diferencia entre las siguientes?

 #define FALSE 0 #define TRUE 1 // Option 1 #define TRUE !FALSE // Option 2 

Del ejemplo vivo aquí , no parece hacer una diferencia. ¿Hay algún beneficio técnico para cualquiera de las opciones? (Sin incluir el hecho de que el segundo ejemplo funcionaría mejor con los objetos bool c ++).

ISO C y C99 ambos definen ! al igual que.

El resultado del operador de negación lógica! es 0 si el valor de su operando se compara con 0, 1 si el valor de su operando se compara con 0. El resultado tiene el tipo int. La expresión! E es equivalente a (0 == E).

Entonces !0 evalúa a 1 . Dado un comstackdor de C que cumpla con los estándares, ambas opciones tendrán el mismo resultado. Además, no hay penalización de tiempo de ejecución, los comstackdores se retirarán constantemente !0 a 1 en el momento de la comstackción.


Si desea llevar esto al extremo lógico y no hacer suposiciones acerca de lo verdadero o lo falso son …

 #define TRUE (1==1) #define FALSE (!TRUE) 

Esto tiene la ventaja de ser siempre verdadero sin importar el idioma. Por ejemplo, en el shell 0 generalmente se considera “verdadero” o “no es un error”.

Este tipo de cosas es un anacronismo de una época en que C no tenía un estándar acordado. Por ejemplo, la primera edición de Code Complete recomienda esto en la página 369. Cuando se publicó en 1993, era probable que su comstackdor de C no fuera compatible con ISO y que stdbool.h no existiera. “Código Completo” también está destinado al progtwigdor políglota que trabaja en muchos idiomas diferentes. Algunos, como shell y Lisp, definen la verdad de manera diferente.

No hay beneficio para la opción 2, como ! 0 ! 0 está garantizado por el estándar C para evaluar a 1.

Definir TRUE de esa manera es un elemento básico de fonts antiguas, presumiblemente en un bash de seguir la guía de estilo que exige evitar “constantes mágicas” siempre que sea posible.

No mucha diferencia.

#define TRUE 1 tiene una ligera ventaja sobre #define TRUE !FALSE en que 1 es un elemento único que no se ve afectado por la precedencia del operador.

!FALSE podría ser (!FALSE) para hacer frente al código arcano que intenta utilizar ++ -- [] . -> ++ -- [] . -> , que tienen mayor precedencia al lado de FALSE .

 #define FALSE 0 #define TRUE 1 // Option 1 #define TRUE !FALSE // Option 2 

No hay diferencia en los valores. Tanto 1 como !0 son expresiones constantes de tipo int con el mismo valor, 1 (según la definición estándar de la semántica del operador ! ).

Existe una posible diferencia en que la segunda definición no está correctamente entre paréntesis. Recuerde que la expansión de macros se realiza textualmente. La expansión de una macro sin paréntesis en medio de una expresión puede llevar a problemas de precedencia del operador. He escrito un ejemplo artificial aquí .

¡Desde el unario ! El operador tiene una prioridad muy alta, no es probable que se encuentre con un problema. El único caso que se me ocurre es si lo usa como un prefijo para el operador de indexación. Por ejemplo, dado:

 int arr[] = { 10, 20 }; 

Opción 1 da:

 TRUE[arr] == 20 

mientras que la opción 2 da:

 TRUE[arr] == 0 

Para ver por qué, recuerde que la indexación de matrices es conmutativa (vea esta pregunta y mi respuesta , y que el operador de indexación [] enlaza más estrechamente que !

Las lecciones aquí son:

  1. Para cualquier macro que se pretenda usar como una expresión, toda la definición de la macro debe estar entre paréntesis, incluso si no puede pensar en un caso en el que sea importante.

  2. Mantenlo simple. En C, 0 es el único valor falso, y 1 es el valor verdadero canónico. (Cualquier valor distinto de cero es “verdadero”, pero los operadores “booleanos” incorporados siempre dan 0 o 1 ). ¡Usando el ! El operador que defina TRUE en términos de FALSE (o viceversa) es solo una complicación innecesaria.

Usa si puedes. Si no puedes (porque estás atascado con un comstackdor pre-C99), te recomiendo esto:

 typedef enum { false, true } bool; 

No es exactamente lo mismo que _Bool / bool C99 (las conversiones a este tipo de bool no están normalizadas a 0 o 1 ), pero son lo suficientemente cercanas para casi todos los propósitos.

En el lenguaje C, TRUE se define correctamente como (! FALSO) porque mientras que cero (0) es FALSO y FALSO es cero (0), cualquier otro valor es VERDADERO. Puede usar casi cualquier variable como una expresión booleana, y si no es cero, el valor de la expresión es VERDADERO. Un puntero NULO es cero por esa misma razón. Así es el carácter de fin de cadena (‘\ 0’). Hay una gran cantidad de código escrito para aprovechar este hecho. Considerar:

 while ( *d++ = *s++ ); 

La copia finalizará cuando se copie el carácter de fin de cadena. Este idioma es muy común. No importa los problemas de tamaño del búfer.

Esta es una de las razones por las que es una mala idea probar si la igualdad es VERDADERA si no tiene un tipo booleano dedicado moderno donde los únicos valores posibles sean VERDADERO y FALSO. Te sugiero que hagas un hábito para probar la desigualdad en FALSO de todos modos, por razones de seguridad. Es posible que no siempre llegues a trabajar con lo nuevo y shiny.

Ellos son los mismos.

  • !0 es 1 entonces !FALSE es 1

#define TRUE !FALSE no tiene ningún beneficio técnico en absoluto, aunque existió durante mucho tiempo y apareció en muchos lugares.

#define TRUE !FALSE se puede malinterpretar, se podría pensar que TRUE representa cada valor que no sea 0 .

  • Solo 1 es igual a TRUE , otros valores como 2 , 3 , 255 … (que !=0 ) no es igual a TRUE

Para evitar este malentendido , muchas organizaciones requieren que no se use #define TRUE !FALSE o la comparación con TRUE debe cambiar a !FALSE :

 // Should not if (var_bool == TRUE) { ... } //Should if (var_bool != FALSE) { ... }