Acabo de llegar a un proyecto con una base de código bastante grande.
Principalmente estoy tratando con C ++ y gran parte del código que escriben usa doble negación para su lógica booleana.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
Sé que estos tipos son programadores inteligentes, es obvio que no están haciendo esto por accidente.
No soy un experto experimentado en C ++, mi única suposición de por qué están haciendo esto es que quieren hacer absolutamente positivo que el valor que se evalúa es la representación booleana real. Entonces lo niegan, luego lo niegan nuevamente para volver a su valor booleano real.
¿Es correcto o me falta algo?
Respuestas:
Es un truco convertir a bool.
fuente
bool
tipo, para ayudar a evitar almacenar valores distintos de1
y0
en variables booleanas.!!
o!=0
resuelve el problema, y entre los dos encuentro el ex limpiador (ya que funcionará en una mayor cantidad de tipos). También estoy de acuerdo en que no hay ninguna razón para usar tampoco en el código en cuestión.En realidad, es un idioma muy útil en algunos contextos. Tome estas macros (ejemplo del kernel de Linux). Para GCC, se implementan de la siguiente manera:
¿Por qué tienen que hacer esto? GCC
__builtin_expect
trata sus parámetros comolong
y nobool
, por lo que debe haber alguna forma de conversión. Como no saben quécond
es cuando escriben esas macros, lo más general es simplemente usar el!!
idioma.Probablemente podrían hacer lo mismo comparando con 0, pero en mi opinión, en realidad es más sencillo hacer la doble negación, ya que es lo más cercano a un cast-to-bool que tiene C.
Este código también se puede usar en C ++ ... es una cosa de mínimo común denominador. Si es posible, haga lo que funciona tanto en C como en C ++.
fuente
Los codificadores piensan que convertirá el operando a bool, pero debido a que los operandos de && ya están implícitamente convertidos a bool, es completamente redundante.
fuente
Es una técnica para evitar escribir (variable! = 0), es decir, convertir de cualquier tipo que sea a un bool.
El código IMO como este no tiene cabida en los sistemas que deben mantenerse, porque no es un código legible de inmediato (de ahí la pregunta en primer lugar).
El código debe ser legible; de lo contrario, dejará un legado de deuda temporal para el futuro, ya que lleva tiempo comprender algo que es innecesariamente complicado.
fuente
bool(expr)
: hace lo correcto y todos entienden la intención a primera vista.!!(expr)
es una doble negación, que accidentalmente se convierte en bool ... esto no es simple.Sí, es correcto y no, no te estás perdiendo algo.
!!
Es una conversión a bool. Vea esta pregunta para más discusión.fuente
Evita una advertencia del compilador. Prueba esto:
La línea 'bar' genera un "valor de forzamiento para bool 'verdadero' o 'falso' (advertencia de rendimiento)" en MSVC ++, pero la línea 'baz' se cuela bien.
fuente
bool
tipo: todo está codificado como0
o1
en unint
.Es operador! ¿sobrecargado?
Si no, probablemente estén haciendo esto para convertir la variable en un bool sin generar una advertencia. Definitivamente, esta no es una forma estándar de hacer las cosas.
fuente
Desarrolladores legado C no tenían ningún tipo booleano, lo que a menudo
#define TRUE 1
y#define FALSE 0
a continuación, utilizan tipos de datos numéricos arbitrarios para las comparaciones booleanas. Ahora que lo tenemosbool
, muchos compiladores emitirán advertencias cuando se realicen ciertos tipos de asignaciones y comparaciones utilizando una mezcla de tipos numéricos y tipos booleanos. Estos dos usos eventualmente colisionarán cuando se trabaje con código heredado.Para solucionar este problema, algunos desarrolladores usan la siguiente identidad booleana:
!num_value
devuelvebool true
ifnum_value == 0
;false
de otra manera.!!num_value
devuelvebool false
sinum_value == 0
;true
de otra manera. La única negación es suficiente para convertirnum_value
abool
; sin embargo, la doble negación es necesaria para restaurar el sentido original de la expresión booleana.Este patrón se conoce como modismo , es decir, algo comúnmente utilizado por personas familiarizadas con el idioma. Por lo tanto, no lo veo como un antipatrón, tanto como lo haría
static_cast<bool>(num_value)
. El elenco podría muy bien dar los resultados correctos, pero algunos compiladores luego emiten una advertencia de rendimiento, por lo que aún debe abordar eso.La otra manera de abordar esto es decir,
(num_value != FALSE)
. También estoy de acuerdo con eso, pero en general,!!num_value
es mucho menos detallado, puede ser más claro y no es confuso la segunda vez que lo ve.fuente
!!
se utilizó para hacer frente a C ++ original que no tenía un tipo booleano (como tampoco lo hizo C).Problema de ejemplo:
En
if(condition)
el interior , lacondition
necesidad de evaluar a algún tipo comodouble, int, void*
, etc., pero nobool
como todavía no existe.Digamos que existía una clase
int256
(un entero de 256 bits) y todas las conversiones / conversiones de enteros estaban sobrecargadas.Para probar si
x
era "verdadero" o distinto de cero,if (x)
convertiríax
a algún número entero y luego evaluaría siint
era distinto de cero. Una sobrecarga típica de(int) x
devolvería solo los LSbits dex
.if (x)
entonces solo estaba probando los LSbits dex
.Pero C ++ tiene el
!
operador. Una sobrecarga!x
típicamente evaluaría todos los bits dex
. Entonces, para volver a la lógica no invertidaif (!!x)
se utiliza.Ref. ¿Las versiones anteriores de C ++ utilizaron el operador `int` de una clase al evaluar la condición en una instrucción` if () `?
fuente
Como mencionó Marcin , bien podría importar si la sobrecarga del operador está en juego. De lo contrario, en C / C ++ no importa, excepto si está haciendo una de las siguientes cosas:
comparación directa con
true
(o en C algo así como unaTRUE
macro), que casi siempre es una mala idea. Por ejemplo:if (api.lookup("some-string") == true) {...}
simplemente desea que algo se convierta en un valor estricto de 0/1. En C ++, una asignación a una
bool
voluntad hará esto implícitamente (para aquellas cosas que son implícitamente convertibles abool
). En C o si se trata de una variable no bool, este es un idioma que he visto, pero prefiero la(some_variable != 0)
variedad yo mismo.Creo que en el contexto de una expresión booleana más grande, simplemente llena las cosas.
fuente
Si la variable es de tipo de objeto, puede tener un! operador definido pero sin conversión a bool (o peor, una conversión implícita a int con semántica diferente. Llamar al operador! dos veces resulta en una conversión a bool que funciona incluso en casos extraños.
fuente
Es correcto pero, en C, no tiene sentido aquí: 'if' y '&&' tratarían la expresión de la misma manera sin el '!!'.
La razón para hacer esto en C ++, supongo, es que '&&' podría estar sobrecargado. Pero entonces, también podría '!', Por lo que no garantiza realmente que obtenga un bool, sin mirar el código para los tipos de
variable
yapi.call
. Quizás alguien con más experiencia en C ++ podría explicarlo; tal vez sea una medida de defensa en profundidad, no una garantía.fuente
if
o&&
, pero el uso!!
puede ayudar en algunos compiladores siif (!!(number & mask))
se reemplaza conbit triggered = !!(number & mask); if (triggered)
; en algunos compiladores integrados con tipos de bits, asignar, por ejemplo, 256 a un tipo de bits producirá cero. Sin la!!
transformación aparentemente segura (copiar laif
condición a una variable y luego ramificar) no será segura.Tal vez los programadores estaban pensando algo como esto ...
!! myAnswer es booleano. En contexto, debería volverse booleano, pero me encanta golpear las cosas para asegurarme, porque había una vez un misterioso error que me mordió, y lo golpeé, lo maté.
fuente
Este puede ser un ejemplo del truco de la doble explosión , vea The Safe Bool Idiom para más detalles. Aquí resumo la primera página del artículo.
En C ++ hay varias formas de proporcionar pruebas booleanas para las clases.
Podemos probar la clase,
Sin embargo,
opereator bool
se considera inseguro porque permite operaciones sin sentido comotest << 1;
oint i=test
.La implementación es trivial,
Las dos formas idiomáticas de probar
Testable
objetos sonLa primera versión
if (!!test)
es lo que algunas personas llaman el truco del doble golpe .fuente
explicit operator bool
para evitar la conversión implícita a otros tipos integrales.