Estoy leyendo un código abierto en C que usa glib y encontré algo como esto
gboolean function() { guint myVar = 0; myVar = (!!globalVar1 + !!globalVar2 + !!globalVar3); return !!myVar; }No entiendo qué está pasando exactamente con ese doble signo de exclamación.
El unario ! El operador realiza una operación lógica NOT. Si su operando es distinto de cero, se evalúa como 0. Si su operando es 0, se evalúa como 1.
Cuando dos de ellos se juntan así, el operando se normaliza a un valor booleano. Entonces, si el operando es 0, el resultado es 0 y si el operando es distinto de cero, el resultado es 1.
En el contexto de la expresión más grande:
myVar = (!!globalVar1 + !!globalVar2 + !!globalVar3); Esto establecerá myVar en un valor entre 0 y 3. Luego esto:
return !!myVar;Normaliza ese valor a 0 o 1. Entonces, el resultado final es que se devuelve 1 si alguna de las 3 variables es distinta de cero; de lo contrario, se devuelve 0.
El cuerpo de la función se puede reescribir como:
return globalVar1 || globalVar2 || globalVar3; Lo que expresa más claramente la intención. el || Sin embargo, el operador implica la bifurcación, por lo que el código tal como está escrito probablemente estaba tratando de evitar esa bifurcación.
Sin embargo, en general, los compiladores son bastante buenos para optimizar, por lo que tales microoptimizaciones no son realmente necesarias.
Primero consideremos esta afirmación
myVar = (!!globalVar1 + !!globalVar2 + !!globalVar3);Ahora de acuerdo con el Estándar C (6.5.3.3 Operadores aritméticos unarios)
5 El resultado del operador de negación lógica ! es 0 si el valor de su operando se compara diferente a 0, 1 si el valor de su operando se compara igual a 0. El resultado tiene tipo int. La expresión !E es equivalente a (0==E)
Por ejemplo, si tienes una variable como esta
int x = 10; luego aplicando el operador ! a la variable !x obtendrás 0. Aplicando por segunda vez el operador !!x obtendrás 1. Lo mismo si se escribe x != 0 .
Entonces, el resultado de la asignación es un valor distinto de cero si al menos uno de los operandos, globalVar1 , globalVar2 y globalVar3 . no es igual a 0.
La afirmación anterior se puede reescribir de la siguiente manera
myVar = ( ( globalVar1 != 0 ) + ( globalVar2 != 0 ) + ( globalVar3 != 0 ) );El resultado de la asignación puede ser 0 (si todos los operandos son iguales a 0), o 1 (si solo un operando es diferente a 0), o 2 (si dos operandos son iguales a 0), o 3 (si todos los operandos son iguales a 0). son iguales a 0).
La función debe devolver 1 si al menos un operando no es igual a 0 o 1 de lo contrario.
Podrías simplemente escribir en la declaración de devolución
return myVar != 0;Pero el autor del código decidió escribir
return !!myVar; ¡Parece que le gusta mucho el operador de negación ! .:)
El propósito de este "acto de equilibrio" con el operador de negación es devolver exactamente 0 o 1.
!!val da 0 si val es cero o 1 si val no es cero.
Ejemplo de uso:
//function counting non zero elelemnts of array size_t countNonZero(const int *array, size_t size) { size_t count = 0; while(size--) count += !!*array++; return count; } En su ejemplo, no hay necesidad de !! operador como en C cualquier valor distinto de cero se considera como true . sencillo || se debe utilizar el operador.
esa función debe reescribirse como
gboolean function() { return globalVar1 || globalVar2 || globalVar3; }