I'm reading an open code in C which uses glib, and I found this
gboolean function()
{
guint myVar = 0;
myVar = (!!globalVar1 !!globalVar2 !!globalVar3);
return !!myVar;
}
I don't understand what's exactly happening with that double exclamation mark.
Thank you in advance.
CodePudding user response:
The unary !
operator performs a logical NOT operation. If its operand is non-zero, it evaluates to 0. If its operand is 0, it evaluates to 1.
When two of them are put together like this, it normalizes the operand to a boolean value. So if the operand is 0 the result is 0 and if the operand is non-zero the result is 1.
In the context of the larger expression:
myVar = (!!globalVar1 !!globalVar2 !!globalVar3);
This will set myVar
to a value between 0 and 3. Then this:
return !!myVar;
Normalizes that value to 0 or 1. So the end result is that 1 is returned if any of the 3 variables are non-zero, otherwise 0 is returned.
The body of the function can be rewritten as:
return globalVar1 || globalVar2 || globalVar3;
Which more clearly expresses the intent. The ||
operator does involve branching however, so the code as written was probably trying to avoid that branching.
Generally though, compilers are pretty good at optimizing, so such micro-optimizations are not really necessary.
CodePudding user response:
Let's at first consider this statement
myVar = (!!globalVar1 !!globalVar2 !!globalVar3);
Now according to the C Standard (6.5.3.3 Unary arithmetic operators)
5 The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E)
For example If you have a variable like this
int x = 10;
then applying the operator !
to the variable !x
you will get 0. Applying the operator the second time !!x
you will get 1. It is the same if to write x != 0
.
So the result of the assignment is a non-zero value if at least one of the operands, globalVar1
, globalVar2
, and globalVar3
. is not equal to 0.
The above statement can be rewritten the following way
myVar = ( ( globalVar1 != 0 ) ( globalVar2 != 0 ) ( globalVar3 != 0 ) );
The result of the assignment can be either 0 (if all operands are equal to 0), or 1 (if only one operand is not equal to 0), or 2 ( if two operands equal to 0), or 3 (if all operands are equal to 0).
The function need to return 1 if at least one operand is not equal to 0 or 1 otherwise.
You could just write in the return statement
return myVar != 0;
But the author of the code decided to write
return !!myVar;
It seems he likes very much the negation operator !
.:)
The purpose of this "balancing act" with the negation operator is to return exactly either 0 or 1.
CodePudding user response:
It's the same as the single exclamation mark, twice. It's negating a value twice.
This has the effect of turning all integers to either 0
(if they were already 0
) or 1
(if they were any non-zero value)
CodePudding user response:
!!val
gives 0
if val
is zero or 1
if val
is not zero.
Example usage:
//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;
}
In your example, there is no need of the !!
operator as in C any non zero value is considered as the true
. Simple ||
operator should be used.
that function should be rewritten as
gboolean function()
{
return globalVar1 || globalVar2 || globalVar3;
}