2010-01-21 11 views
5

Estoy muy feliz de que, en C, este tipo de cosas son malas código:Cómo evitar cuidadosamente C echa a perder la verdad

(var_a == var_b) ? TRUE : FALSE 

Sin embargo, ¿cuál es la mejor manera de tratar con esto:

/* Header stuff */ 
#define INTERESTING_FLAG 0x80000000 
typedef short int BOOL; 

void func(BOOL); 

/* Code */ 
int main(int argc, char *argv[]) 
{ 
     unsigned long int flags = 0x00000000; 

     ... /* Various bits of flag processing */ 

     func(flags & INTERESTING_FLAG); /* func never receives a non-zero value 
             * as the top bits are cut off when the 
             * argument is cast down to a short 
             * int 
             */ 
} 

¿Es aceptable (para cualquier valor de aceptable que esté utilizando) tener (flags & FLAG_CONST) ? TRUE : FALSE?

+4

Creo que el problema aquí es '#define BOOL corta int'. Ha definido un tipo llamado booleano, pero donde los valores distintos de cero se convierten en falso. Entonces ha actuado como si cualquier valor distinto de cero es verdadero. Esa es una abstracción con goteras. –

+0

Realmente no veo qué hay de malo en ese código, es una función de lenguaje estándar que cualquier programador de C debe saber. – Skizz

+1

@Skizz: el problema con '(var1 == var2)? VERDADERO: FALSO; ¿quieres decir? El problema es que se expresa mejor como '(var1 == var2)', suponiendo que TRUE y FALSE tienen valores razonables. –

Respuesta

5

Preferiría (flags & CONST_FLAG) != 0. Mejor aún, use el tipo _Bool si lo tiene (aunque a menudo se disfraza como bool).

+0

¿'_Bool' /' bool' asigna todos los valores distintos de cero a 'true', entonces? No he oído hablar de él antes ... –

+0

@me_and: sí, un molde en _Bool/bool hace que todos los valores distintos de cero sean verdaderos, y cero falsos. Se agregó en C99, pero dado que C++ también tiene 'bool', un buen número de compiladores de C lo incluyen también, aunque no implementan (incluso cerca de) todos los C99. –

+0

Aceptando: tiene una buena opción pre-C99 (que probablemente voy a tener que usar; tengo que ser capaz de compilar compiladores que no sean C99, lamentablemente), y también tiene la solución ideal provista de estándares: D –

0

Se puede evitar esto, un par de diferentes maneras:

En primer lugar

void func(unsigned long int); 

se haría cargo de ella ...

O

if(flags & INTERESTING_FLAG) 
{ 
    func(true); 
} 
else 
{ 
    func(false); 
} 

también lo haría .

EDITAR: (flags & INTERESTING_FLAG) != 0 también es bueno. Probablemente mejor.

4

Establezca las banderas del compilador lo más analíticamente posible, para advertirle de cualquier lanzamiento que pierda bits, y trate las advertencias como errores.

+0

+1. Esto no te dice qué hacer al respecto, pero es importante. –

+0

Eso me dice sobre el problema, pero no lo resuelve ... –

6

En cualquier caso, llamaría func con (flags & INTERESTING_FLAG) != 0 como argumento para indicar que se requiere un parámetro booleano y no el resultado aritmético de flags & INTERESTING_FLAG.

+2

Soy vagamente parcial a ((flags & MASK) == MASK) como una solución general, pero debería dar el mismo resultado que! = 0. – Vatine

+0

@vatine: Eso tiene la desventaja de que las comparaciones con valores distintos de cero son (muy marginalmente) menos eficientes que las comparaciones a cero, ya que una comparación a cero generalmente se puede implementar como una operación de máquina única. No hace mucha diferencia (y con un buen compilador puede no hacer ninguna diferencia), pero aún así ... –

+0

@me_and: No hay diferencia en absoluto con los dos compiladores que acabo de probar. Es una transformación bastante simple para un compilador. –

0

Esto es parcialmente fuera de tema:

También me gustaría crear una función de ayuda que hace que sea obvio para el lector cuál es el propósito de la comprobación es por lo que no llena su código con esta bandera explícita la comprobación de todo sobre el lugar. Typedefing the flag type haría más fácil cambiar el tipo de bandera y la implementación más tarde.

Los compiladores modernos admiten la palabra clave en línea que puede eliminar la sobrecarga del rendimiento en una llamada a función.

typedef unsigned long int flagtype; 
... 
inline bool hasInterestingFlag(flagtype flags) { 
    return ((flags & INTERESTING_FLAG) != 0); 
} 
1

Puede que esta no sea una solución popular, pero a veces las macros son útiles.

#define to_bool(x) (!!(x)) 

Ahora podemos tener todo lo que queremos de forma segura sin temor a rebosar nuestro tipo:

func(to_bool(flags & INTERESTING_FLAG)); 

Otra alternativa podría ser la de definir su tipo booleano ser un intmax_t (de stdint.h), de modo que es imposible para que un valor sea truncado en falsedad

Mientras estoy aquí, quiero decir que usted debe utilizar un typedef para la definición de un nuevo tipo, no un #define:

typedef short Bool; // or whatever type you end up choosing 

Algunos podrían argumentar que se debe utilizar una variable en lugar de const una macro para las constantes numéricas:

const INTERESTING_FLAG = 0x80000000; 

en general hay mejores cosas que puede gastar su tiempo en. Pero macros para typedef s es un poco tonto.

+0

Buen lugar. ¡Utilicé 'typedef' en mi código, y olvidé por completo su propia existencia al escribir esta pregunta! –

4

Algunas personas no les gusta, pero yo uso !!.

es decir

!!(flags & CONST_FLAG) 

(no como una macro to_bool como alguien sugirió, sólo directamente en el código).

Si más personas lo usaran, no sería visto como inusual así que empiece a usarlo !!

+0

No creo que sea extraño o inusual, simplemente no me gusta. Prefiero los operadores con nombre siempre que sea posible ('y' en lugar de' && ',' not' en lugar de '!') Y si veía a alguien escribir 'not not x' en Python, los fotografiaba. La versión del símbolo es más legible, pero todavía no me gusta, y es por eso que lo puse en una macro. –

0

¿Tiene algo en contra de

flags & INTERESTING_FLAG ? TRUE : FALSE 

?

0

Esta es la razón por la que solo debe usar los valores de una manera "booleana" cuando estos valores tienen una semántica booleana explícita. Su valor no satisface la regla, ya que tiene una semántica de entero pronunciada (o, más precisamente, semántica de matriz de bits). Con el fin de convertir dicho valor booleano, compararlo con 0

func((flags & INTERESTING_FLAG) != 0); 
Cuestiones relacionadas