2009-08-21 20 views
73

¿Cuál puede ser una razón para convertir un número entero en un booleano de esta manera?¿Por qué usarlo? al convertir int a bool?

bool booleanValue = !!integerValue; 

en lugar de sólo

bool booleanValue = integerValue; 

Todo lo que sé es que en VC++ 7 éste hará que C4800 warning y el primero no lo hará. ¿Hay alguna otra diferencia entre los dos?

+2

supongo que la pregunta es por qué el primero no causa una C4800 o bien ya que incluso "Echando la expresión de tipo bool no va a desactivar la advertencia, que es por diseño." (MS) – Tobias

+0

um, esto de hecho tiene su lugar ... las personas confunden C++ y C –

+2

Después de la doble negación, se garantiza que el valor es 0 o 1; el valor original puede ser cualquier valor int. –

Respuesta

108

Los problemas con el "!!" idioma es que es escueto, difícil de ver, fácil de confundir con un error tipográfico, fácil de soltar uno de los "!" s, y así sucesivamente. Lo puse en la categoría "mira lo lindo que podemos ser con C/C++".

Simplemente escriba bool isNonZero = (integerValue != 0); ... tenga en cuenta.

+9

+1 para "bool isNonZero = (integerValue! = 0);". Siempre lo odio cuando el código combina ints, dobles, ptrs, etc. con bool's. Son tipos diferentes y deben tratarse como tales. El molde implícito de un bool al tipo numérico es un anchronismo. –

+8

No veo ningún problema con el tratamiento de ints/pointers como bools: es una versión estándar de C/C++, y se debería esperar que cualquier desarrollador experto en ellas lo sepa. Sin embargo, a veces quieres evitar las advertencias del compilador y cosas así, y en esos casos, una comparación de expicit (o un reparto) es definitivamente mucho más preferible que el truco '' 'relativamente oscuro. –

+0

Ints y bools son diferentes. ¿Por qué debería 0 == falso? Es una resaca de los días anteriores al tipo bool. También significa que !! a no necesariamente es igual a lo que es contrario a la intuición. –

13

Porque! IntegerValue significa integerValue == 0 y !! integerValue significa integerValue! = 0, una expresión válida que devuelve un bool. Este último es un elenco con pérdida de información.

49

Históricamente, se ha utilizado el lenguaje !! para asegurar que su bool realmente contenía uno de los dos valores que se esperan de una variable -como bool, debido a que C y C++ no tenían un cierto tipo bool y fingido con int s . Esto es menos un problema ahora con "real" bool s.

Pero el uso de !! es un medio eficaz de documentar (tanto para el compilador y las futuras personas que trabajan en su código) que sí, que realmente tenía la intención de emitir ese int a un bool.

+9

No diría "un medio eficiente de documentación" si el OP ni siquiera entendiera lo que significaba. Una forma mucho mejor sería static_cast (integerValue). – arolson101

+10

El OP probablemente no sabía lo que 'List ' quería decir al principio, tampoco, o '|| ='. '!!' es un modismo muy, muy arraigado en el universo C y C++. Si alguien no lo sabe, él/ella debe aprenderlo, y luego hacer su propia evaluación razonada sobre si usarlo. –

+5

¿Qué pasa con 'bool var = (bool) intVar;'? – bobobobo

5

Un bool solo puede tener dos estados, 0 y 1. Un entero puede tener cualquier estado desde -2147483648 hasta 2147483647 asumiendo un entero de 32 bits con signo. ¡El unario! el operador emite 1 si la entrada es 0 y emite 0 si la entrada es cualquier cosa excepto 0. Entonces! 0 = 1 y! 234 = 0. ¡El segundo! simplemente cambia la salida para que 0 se convierta en 1 y 1 se convierta en 0.

Así que la primera declaración garantiza que booleanValue se establecerá igual a 0 o 1 y ningún otro valor, la segunda declaración no.

+2

Esto es completamente incorrecto. La segunda declaración implica un molde 'int'->' bool' implícito. Esto está bien definido, y cualquier 'int' que no sea cero se convertirá en' true', y 0 se convertirá en 'false'. La advertencia que da VC++ es en realidad una "advertencia de rendimiento" y no tiene nada que ver con esto. –

+0

Creo que estás confundiendo a BOOL con bool. Con bool, obtienes un bool real con un reparto implícito, por lo tanto verdadero o falso. – Recep

+2

Los estados de un bool en C++ no son 1 y 0, sino verdaderos y falsos. –

-1

No hay una gran razón, excepto ser paranoico o gritar a través del código que es un bool.

para el compilador al final no hará la diferencia.

+0

El código generado puede ser "más lento": el número entero requerirá una prueba para ver si es cero. Sin embargo, para un booleano que se representa como 0/1 binario, no se necesita ninguna prueba. –

+2

Pero, bueno, con esta lógica deberíamos tener una advertencia de rendimiento para cada llamada de función virtual ... – gimpf

+0

Es posible que desee leer eso: http://stackoverflow.com/a/1847949/62921 – ForceMagic

-2

Nunca me ha gustado esta técnica de conversión a un tipo de datos bool - ¡huele mal!

En su lugar, estamos utilizando una plantilla práctica llamada boolean_cast que se encuentra here. Es una solución flexible que es más explícito en lo que está haciendo y se puede utilizar del siguiente modo:

bool IsWindow = boolean_cast<bool>(::IsWindow(hWnd)); 
+8

Es un poco exagerado no es así? Quiero decir, al final del día la conversión a bool es una pérdida de precisión y se reduce a algo así como return b? verdadero Falso; ¿Cuál es casi lo mismo que? VERDADERO Personalmente, esto es un fetiche de STL sobredimensionado. –

+0

Supongo que no está de acuerdo con usar boolean_cast entonces (de ahí el voto abajo) - ¿qué sugieres que usemos entonces? – Alan

+4

Le sugiero que use el idioma como estaba destinado a ser utilizado. Alto rendimiento y desagradable. Solo corta el BS y haz el trabajo. –

4

!! es una forma idiomática para convertir a bool, y funciona a callar sillywarning el Visual C++ del compilador sobre la supuesta ineficacia de tales conversión.

Veo por las otras respuestas y comentarios que muchas personas no están familiarizadas con la utilidad de esta frase idiomática en la programación de Windows. Lo que significa que no han hecho ninguna programación seria de Windows. Y asuma ciegamente que lo que han encontrado es representativo (no lo es).

#include <iostream> 
using namespace std; 

int main(int argc, char* argv[]) 
{ 
    bool const b = static_cast<bool>(argc); 
    (void) argv; 
    (void) b; 
} 
 
> [d:\dev\test] 
> cl foo.cpp 
foo.cpp 
foo.cpp(6) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning) 

[d:\dev\test] 
> _ 

y al menos una persona piensa que si un novato total no reconoce su significado, entonces es no bueno. Bueno, eso es estúpido. Hay muchas cosas que los novatos absolutos no reconocen ni entienden. Escribir el código de uno para que sea entendido por cualquier novato no es algo para profesionales. Ni siquiera para los estudiantes. Empezar en el camino de excluir operadores y combinaciones de operadores que los principiantes no entienden ... Bueno, no tengo las palabras para darle a ese enfoque una descripción apropiada, lo siento.

Saludos & HTH.,

13

Se utiliza porque el lenguaje C (y un poco de C++ estándar pre-compiladores también) no tenían el tipo bool, simplemente int. Por lo tanto, int s se usaron para representar valores lógicos: se suponía que 0 significaba false, y todo lo demás era true. El operador ! devolvía 1 de 0 y 0 de todo lo demás. Se usó Double ! para invertirlos, y estaba allí para asegurarse de que el valor sea solo 0 o 1 dependiendo de su valor lógico.

En C++, desde la introducción de un tipo adecuado bool, ya no hay necesidad de hacerlo. Pero no puedes simplemente actualizar todas las fuentes heredadas, y no deberías hacerlo, debido a la compatibilidad con versiones anteriores de C con C++ (la mayoría de las veces). Pero muchas personas todavía lo hacen, por el mismo motivo: para mantener su código compatible con versiones anteriores de compiladores antiguos que aún no entienden bool s.

Y esta es la única respuesta real. Otras respuestas son engañosas.

+0

Eso estaba claro. +1 :) – zx81

6

Otra opción es el operador ternario que aparece para generar una línea menos de código de montaje (en Visual Studio 2005 de todos modos):

bool ternary_test = (int_val == 0) ? false : true; 

que produce el código de montaje:

cmp DWORD PTR _int_val$[ebp], 0 
setne al 
mov BYTE PTR _ternary_test$[ebp], al 

Versus:

bool not_equal_test = (int_val != 0); 

que produce:

xor eax, eax 
cmp DWORD PTR _int_val$[ebp], 0 
setne al 
mov BYTE PTR _not_equal_test$[ebp], al 

Sé que no es una gran diferencia, pero tenía curiosidad y pensé que compartiría mis conclusiones.

1

La respuesta de user143506 es correcta, pero para un posible problema de rendimiento que comparó los possibilies en asm:

return x;, return x != 0;, return !!x; e incluso return boolean_cast<bool>(x) resultados en esta perfecto conjunto de instrucciones asm:

test edi/ecx, edi/ecx 
setne al 
ret 

Esto se probó para GCC 7.1 y MSVC 19 2017. (Solo el booleano_convertidor en MSVC 19 2017 da como resultado una cantidad mayor de código asm, pero esto es causado por la templatación y las estructuras y puede descuidarse desde el punto de vista del rendimiento, porque el mismo lin es como se indicó anteriormente puede duplicarse para diferentes funciones con el mismo tiempo de ejecución.)

Esto significa que no hay diferencia de rendimiento.

PS: Se utilizó este boolean_cast:

#define BOOL int 
// primary template 
template< class TargetT, class SourceT > 
struct boolean_converter; 

// full specialization 
template< > 
struct boolean_converter<bool, BOOL> 
{ 
    static bool convert(BOOL b) 
    { 
    return b ? true : false; 
    } 
}; 

// Type your code here, or load an example. 
template< class TargetT, class SourceT > 
TargetT boolean_cast(SourceT b) 
{ 
    typedef boolean_converter<TargetT, SourceT> converter_t; 
    return converter_t::convert(b); 
} 

bool is_non_zero(int x) { 
    return boolean_cast<bool>(x); 
}