Suppose we have an int and want to toggle it between 0 and 1 in a boolean fashion. I thought of the following possibilities:
int value = 0; // May as well be 1
value = value == 0 ? 1 : 0;
value = (value + 1) % 2;
value = !value; // I was curious if that would do...
The third one seems to work. Why? Who decides that !0 is 1?
Is something wrong with any of these?
Are there other possibilities? e.g. bitwise operators?
Which offers the best performance?
Would all that be identical with _Bool (or bool from stdbool.h)? If not, what are the differences?
EDIT: Many great answers with lots of valuable information, thanks! Unfortunately, I can only accept one.
value = !value; expresses what you want to do directly, and it does exactly what you want to do by definition.
Use that expression.
From C99 6.5.3.3/5 "Unary arithmetic operators":
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).
The third one seems to work. Why? Who decides that !0 is 1?
C Standard guarantees that !0 is 1.
Are there other possibilities? e.g. bitwise operators?
Yes, you can use the exclusive OR operator:
value ^= 1;
By the way I prefer this to value = !value; as relational and equality operators can result to branching and bitwise operators usually do not.
value = 1 - value; // toggle from 0 to 1 ... or 1 to 0
// when you know initial value is either 0 or 1
the language was designed that way.
Use the 3rd one, the others are right but unnecessarly complicated and therefore hiding the intent.
value = (value ^ 1) & 1;
They're all the same after optimisation.
_Bool would have the same results. The only thing different with _Bool is that values are coerced to be either 1 or 0. Meaning that bool x = 55; will have the value x == 1
EDIT: Corrected the formula in 3 because of my brainfart. I let the comments so that people can see my blooper.
value = !value seems the most reasonable one, but you can also use value = 1 - value or value ^= 1. But the last two would both break if value is not 0 or 1. The first one would still work.
There can be noticeable performance issues with the alternatives depending on the architecture:
!a might need in some architectures comparison and branching, which can be expensive depending on the pattern of 'a'
on some architectures there is conditional move (which is branchless), but
which may require still 3 instructions to complete (with dependencies)
1-a most likely needs two instructions in many architectures
counter example: ARM has reverse subtraction RSB %r0, %r0, #1
1^a can be implemented in many architecture with a single instruction
a=(a+1) % 2 will be most likely optimized to a=(a+1)&1, which requires 2 instructions
But anyway the first rule of optimization is that don't optimize a non working code.
To replace !a with a^1, one has to be 100% certain that it produces always the expected value.
Your expression value = value == 0 ? 1 : 0; will work exactly like value = !value;. You can use any of the two.
!0 is always 1 and also !(any non zero value) is 0
Use bitwise NOT operator
var = ~var;
Related
I was reading a kernel code, and in one place I've seen an expression inside if statement like
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
where SPINLOCK_SHARED = 0x80000000 is a predefined constant.
I wonder why do we need (SPINLOCK_SHARED | 1) - 1 - for type conversion purpose? the result of the expression would be 80000000-- same as 0x80000000, is it not? yet, why ORing 1 and Subtracting 1 matters?
Have a feeling like I am missing to get something..
The code is found in _spin_lock_contested, which is called from _spin_lock_quick when someone else is attempting to obtain the lock :
count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
_spin_lock_contested(spin, ident, count);
}
If there's no contest, then count (the previous value) should be 0, but it isn't. This count value is passed as parameter to _spin_lock_contested as the value parameter. This value is then checked with the if from the OP :
/*
* WARNING! Caller has already incremented the lock. We must
* increment the count value (from the inline's fetch-add)
* to match.
*
* Handle the degenerate case where the spinlock is flagged SHARED
* with only our reference. We can convert it to EXCLUSIVE.
*/
if (value == (SPINLOCK_SHARED | 1) - 1) {
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
return;
}
Keeping in mind that value is the previous value of spin->counta, and the latter has already been incremented by 1, we expect spin->counta to equal value + 1 (unless something has changed in the meantime).
So, checking if spin->counta == SPINLOCK_SHARED | 1 (the precondition of the atomic_cmpset_int) corresponds to checking if value + 1 == SPINLOCK_SHARED | 1, which can be rewritten as value == (SPINLOCK_SHARED | 1) - 1 (again, if nothing has changed in the meantime).
While value == (SPINLOCK_SHARED | 1) - 1 could be rewritten as value == SPINLOCK_SHARED, it's left as is, to clarify the intent of the comparison (ie. to compare the incremented previous value with the test value).
Or iow. the answer appears to be : for clarity and code consistency.
I think the goal is probably to ignore the lowest significant bit:
If SPINLOCK_SHARED expressed in binary is xxx0 -> result is xxx0
If SPINLOCK_SHARED = xxx1 -> result is also xxx0
would have been perhaps clearer to use a bit mask expression ?
The effect of
(SPINLOCK_SHARED | 1) - 1
is to ensure that the low-order bit of the result is cleared prior to the comparison with value. I agree that it seems rather pointless but apparently the low-order bit has a particular usage or meaning which is not apparent in this code, and I think we have to assume that the devs had a good reason for doing this. An interesting question would be - is this same pattern (| 1) -1) used throughout the codebase you're looking at?
It's an obfuscated way of writing a bit mask. Readable version: value == (SPINLOCK_SHARED & ~1u).
It was just done that way for clarity, that's all. It's because atomic_fetchadd_int() (in e.g. sys/spinlock2.h) returns the value PRIOR to the addition/subtraction, and that value is passed to _spin_lock_contested()
Note that the C compiler completely pre-calculates all constant expressions. In fact, the compiler can even optimize-out inlined code based on conditionals that use passed-in procedure arguments when the procedures are passed constants in those arguments. This is why the lockmgr() inline in sys/lock.h has a case statement.... because that entire case statement will be optimized out and devolve into a direct call to the appropriate function.
Also, in all of these locking functions the overhead of the atomic ops dwarf all other calculations by two or three orders of magnitude.
-Matt
Most like this is done to handle several additional cases. For example, in this case, we say that SPINLOCK_SHARED can not be 1:
int SPINLOCK_SHARED = 0x01
int res = (SPINLOCK_SHARED | 1) - 1 // 0
While looking through some code today, I came across an interesting(unecessary?) method for setting a variable: Adding a logical AND to the value.
LED_GRN = (ivLEDGrnSequence & ivLEDSlot) && 1;
I looked around a bit more for some of these occurrences and found them throughout the code, but in different forms:
As an argument for a function:
isoAgCmdHideShow(iObjectID,( (ecu.l & sVar->mask) && 1), (uint8_t *)TxMsg.buf);
In a conditional:
if( (usbQueue.selection & USB_SELECTION_CAN_1) && 1 ) {return TRUE;}
Does this extra logical AND actually change anything about the code, or is it just superfluous? I tried searching for this online, but the closest I found to an answer is Short-Circuit Evaluation which doesn't seem to apply in these situations because short-circuiting a 1 is useless.
In short, what does Logical AND 1 do for variable declaration?
This appears to be a trick to force any non-zero number to 1, while keeping zeros - alongside a more common !!(expr) idiomatic construct.
The idea is to set LED_GRN to 1 or 0 based on the value of ivLEDGrnSequence & ivLEDSlot.
Other ways to do the same thing are as follows:
LED_GRN = !!(ivLEDGrnSequence & ivLEDSlot);
LED_GRN = (ivLEDGrnSequence & ivLEDSlot) != 0;
Doing x && 1 produces either 1 or 0, regardless of what non-zero value the left operand evaluates to.
From the C standard:
§6.5.13 Logical AND operator
The && operator shall yield 1 if both of its operands compare unequal
to 0; otherwise, it yields 0. The result has type int.
It's converting the result of the bitwise AND to either 0 or 1. The result of the bitwise AND can be 0 or any non-zero number. But after the logical AND, the result can only be 0 or 1.
So the first two examples may be useful. The third example with the if statement is definitely not useful, since if converts the expression to a boolean.
The result of logical operation (in this case &&) is either 0 or 1. The result of arithmetic or bitwise operation (& in this case) is 0 or non-0. If we want to convert any non-0 to 1 we perform a logical operation on it. The more common and idiomatic way to accomplish this is the double negation:
LED_GRN = !!(ivLEDGrnSequence & ivLEDSlot);
I had a controversy about what compilers "think" about this:
a = 8;
b = !!a;
So, is b == 0x01 ? Is TRUE always 0x01 or it may be 0xFF, 0xFFFF, 0xFFFFFFFF etc..?
If I want to extract only 0x00 if (a == 0) and 0x01 if (a > 0) does this double negation approach works?
In other words: to obtain result only 0 or 1, what is better to use?
a) a>0?1:0;
b) !!a
I hope you understand my question.
You have not supplied enough information to tell whether !!a works for your purposes or not.
You stated that you really need the result of a > 0. However, this is not equivalent to !!a if a is signed and holds a negative value. If this is possible, then the answer is obviously "no".
!!a is equivalent to a != 0, not to a > 0.
Yes, b == 1. The result of any boolean operator is always 0 or 1. You can do better though...
I want to extract only 0x00 if (a == 0) and 0x01 if (a > 0)
b = a > 0; most accurately reflect your rule.
!!a will be either 0 or 1, and will be type int. It will be 0 for zero a, and 1 otherwise.
As for your choices (a) and (b), they are not equivalent, due to a possibility of a being negative. That aside, you could argue that a > 0 ? 1 : 0 is clearer but in performance-critical applications !!a may be better as it will not branch whereas a ternary conditional could dump the pipeline. But a good compiler will optimise out either way. I seldom use either since things like if (a) and if (!!a) are functionally equivalent.
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). C11 §6.5.3.3 5
b below will typical have the value of 1 (or possible -1, see below).
a = 8;
b = !!a;
So, is b == 0x01?
Yes (* see below)
Is TRUE always 0x01 or it may be 0xFF, 0xFFFF, 0xFFFFFFFF etc..?
In <stdbool.h>, true is a macro with the integer constant 1. TRUE is not defined by the C standard. Various implementations defines it with the value of 1. It might be have other values. It certainly should be non-zero.
what is better to use?
A) a>0?1:0
B) !!a
Both result in an int with the value of 0 or 1. A reasonable to good compiler would be expected to generate the same code for both (if a in not signed). Use the form that 1) adhere to your groups coding standard or else 2) best conveys the meaning of code at that point. A third option which results in type (bool):
C) (bool) a
If a is signed , then a>0?1:0 is not equivalent to !!a. a != 0 ? 1 :0 is equivalent of !!a.
* If b is a 1 bit signed bit field, b = !!8 will have the value of -1.
In teems of speed I think this is highly dependent on the compiler and processor you are using.
The longer expression would produce an executable 4 - 16 bytes larger.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Can anyone tell me how does this code work?
int Calc(int *arr, int m)
int result;
for (result &= 0; m; (arr[--m] & (0x1 << 0x1F)) ? result += arr[m]: Void());
return result;
I can't understand for loop:/
Where did you find this code so I can hunt that person down and beat him with a copy of Schildt?
It's no surprise you don't understand the loop; it wasn't written to be understandable. The only place this kind of code is acceptable is the IOCCC, except it's not obfuscated enough for that competition.
Taking each bit in turn:
result &= 0;
is a really funky way of initializing result to 0; it's shorthand for result = result & 0, which performs a bitwise-AND of result against 0 (giving 0) and assigns the result back to result. It's also unsafe, since an uninitialized object may contain a trap representation. That should have been written as simply result = 0.
m;
just checks the current value of m; the loop will run until it is 0. The loop basically starts at the last element and works its way down to the first.
(arr[--m] & (0x1 << 0x1F)) ? result += arr[m]: Void()
Ugh. So, the first thing it does is take the value of the array at index m-1 and does a bitwise and against 0x1 << 0x1F (1 shifted left 31 postitions, or essentially 0x80000000); if the result of this operation is non-zero, then we add the value of that array element to result, otherwise we execute some incredibly inappropriately named function that hopefully returns a 01. Given that we're dealing with signed integers, and that on most platforms an int is 32 bits wide, this code is obviously adding up negative values in result.
A slightly saner way of writing that would be
result = 0;
while ( m ) // or m != 0, or m > 0, whatever you prefer
{
if ( arr[--m] < 0 )
result += arr[m];
}
1. The conditional operator ?: isn't meant to be used as a control structure like this. The syntax is expr1 ? expr2 : expr3. First, expr1 is evaluated and all side effects applied; if it results in a non-zero value, then the result of the expression is expr2; otherwise, the result is expr3.
Part 1
Firstrly result &= 0 is used for setting 0 to result variable using bitwise AND operation. Bitwise with 0 will ever return 0.
You can write it simply this way: result = 0
The better (much optimal) way of doing this is: result ^= result. (Bitwise XOR)
Part 2
This loop will iterate while m is greater (or less) than 0. Because m expression will return true if m != 0.
Much secure way of doing it is m > 0.
Also you can use this expression, which is not making programm much optimal, but it will be cleaner to another programmer to understand your code: !!m (casting m variable to bool), which is equal to m != 0;
Part 3
In this part ternary operator (logical_expression ? expression_1 : expression_2) is used.
If logical_expression is true, then expression_1 will be executed, expression_2 will be executed otherwise.
So in your code, if this expression (arr[--m] & (0x1 << 0x1F)) returns true then we add arr[m] to result variable. And do nothing in another case.
Also m variable is decremented in ternary logical expression (arr[--m]).
Sometimes I want to do something like this (with i and j being ints).
(if i==4 && j==9)
{
...
}
Where it'll go through the brackets if i equals 4 and j equals 9. I've been using a single ampersand (&) instead of a double one and my code's been compiling and running.
Is it doing the same thing as a double ampersand &&, and if not what has it been doing?
Edit: Oh and I've been doing the same thing with or, using '|' instead of '||'
Presumably you mean if (i==4 && j==9).
Under the circumstances, changing this from && to & shouldn't change much. The big thing that'll change is that with &&, the j==9 would only be evaluated if the i==4 part was true, but with &, they'll both be evaluated regardless.
When you have something like if (x != NULL && x->whatever ...) you want to ensure that the second part (that dereferences x) is only evaluated if x is not a null pointer. In your case, however, comparing what appear to be ints is unlikely to produce any problems.
It's also possible to run into a problem when you're dealing with something that may produce a value other than 1 to signal true. Again, it's not a problem here because == will always produce either 0 or 1. If (for example) you were using isalpha, islower, etc., from <ctype.h>, they're only required to produce 0 or non-zero values. If you combined those with a &, you'd get a bit-wise or which could produce 0 for two non-zero inputs (e.g., 1 & 2 == 0, but 1 && 2 == 1).
When you use bitwise and on the results from ==, you're going to get 0 & 0 or 0 & 1 or 1 & 0 or 1 & 1. 1 & 1 will yield 1 (true). All the others will yield 0 (false) --- just like && would have.
It's performing a bitwise AND.
What it's doing is the expression i == 4 is equivalent to 1 if i is 4 and the same for the RHS (with j and 9, obviously). The & operator returns the number where both operands have that bit on.
It works the same as && because 00000001 & 00000001 (slimmed down to a byte for example) is the same. If one is 0 (the condition was false), then the & won't see two bits turned on for both operands, and 00000000 is 0, which is falsey.
However, do not simply use & because it's one character shorter or similar. Use it because it expresses what you want to achieve. If it's a logical AND you want, use &&.
The same thing applies to |, except instead of a resulting bit if each operand has it turned on, it turns it on if either operand has that bit turned on.
A single ampersand does a bitwise AND. Every bit of the result is set only if both operands have a 1 in that position.
Since comparisons in C return 1 for true and 0 for false, & will give the same results as && as long as both operands are comparisons. But for arbitrary values, it will return seemingly random results. 1 && 2 is true, but 1 & 2 is false because the binary representations of 1 and 2 have no bits in common.
A single ampersand is called a bitwise and. It is a binary operator that 'ands' two numbers bit by bit.
For instance, if you have two binary numbers, 01100010 and 00011111, your bitwise and will result in 00000010
i==4 returns 1 (true), as does j==9. So, i==4 & j==9 is really just 1 & 1, which evaluates to 1 (true).
Try these examples to see the difference
1) int k = 4 & 6; vs int k = 4 && 6;
2) if(i==4 && 2) vs if(i==4 & 2)