Question

What are the benefits of, for example writing the first statement vs second statement:

First statement:

ANCON1 = ~0x0C;

Second statement:

ANCON1 = 0xF3;

I'm seeing the second as a clear choice I would have made, cause it's more straight forward then the first one. Why use One's Complement when it's so simpel to just write what we want.

Was it helpful?

Solution

Benoit pretty much said it. One is the complement, all but these bits, the other is just these bits.

something&=~3;

Often means you are focusing on those two bits where 0xFC is a focus on the other bits. the ~ version maps directly to a bit clear instruction on some platforms that have it making the author feel better about writing it this way perhaps. And the ~ version is less prone to bugs and mistakes, if you change the size of the variable (without moving these two bits) your code still works, using 0xFC the code is broken and has to be touched everywhere the variable is used. (using a #define to hide the constant makes this worse to debug. it might make it better if the define is reused, but the damage is already done).

At the end of the day though it is a style thing just like

if(!(x&something) {

vs

if((x&something)==0) {

vs

if(x&something) ; else {

In a drawing or painting class you are likely to be taught to focus on the negative, the background, dont draw the outline of the object, but the outline of what is not the object.

In college (electrical engineering, at least decades ago before computer engineering existed) we were encouraged to think in terms of negative logic. Sometimes asserted means positive logic sometimes negative logic and dont think only one way. (same goes for thinking asserted or on is a positive voltage, VCC, and deasserted or off is ground)

With this bitwise operation in particular be able to read code either way, "I am zeroing these bits" vs "I am not zeroing these bits". Because both are correct, just a style difference.

It is just as "simple" to write the 0xC as 0xF3, if you are told verbally for example or a datasheet says bits[3:2] are something and this and that when zero. It is not a stretch for the brain to process that as 0xC, to process it as 0xF3 you have to find more information as to the length of the thing and then process the bits before and after before reaching 0xF3. Or you did the 0xF3 in your head from the 0x0C and you could have just used ~0x0C and saved the step. If there is a diagram showing all the bits side by side with fields marked then it becomes a glass is half empty or half full thing, you and your eyes may easily focus on the negative and pull 0xF3 directly or focus on 0x0C and then invert to get 0xF3 or focus on 0xF3 and have to invert to get 0x0C.

The two advantages one far less important than the other is that on a few processors it ties directly to an instruction and the optimizer doesnt have to work as hard, (micro optimization), the other is a habit to avoid software bugs. If you used an int a handful of years ago with 0xFFFFFFF3, then compiled that code today with no modifications against a 64 bit machine you may have walked yourself into a bug. if that method was used habitually across the code then there is a lot of porting to do. If ~0xC had been used then that code might have ported more smoothly. One implies the size of the variable the other does not.

OTHER TIPS

I read the first one All but 00001100 and the second 11110011. I find it easier to understand what bits are NOT set mentally, because there are fewer.

There's no difference because both values are constant and the first one will be counted and optimized to second one by your compiler. Use the one that makes code more understandable by you and other programmers.

The other thing would be if you used variable-to negate and then to write a variable to the register on most microcontrollers uses 2 commands and to only write a variable to register uses 1.

First of all, ~ means bitwise complement. Don't mix this up with one's complement, one's complement is a way to translate hex to signed integer format.

Regarding good/bad practice, both of your examples are bad, because they are using "magic numbers". The good way to write the same code would be

#define MASK 0x0C

ANCON1 = ~MASK;

Since MASK is something that makes sense and 0xF3 is some random magic number, you should use the former and then invert it.

Note that the ~ operator used on an integer constant is pre-processed at compile time. The actual machine code will still look something like LOADx $F3.

It's typically only a matter of style. The first, x = ~y is an idiom commonly used to denote set all bits in x except those in y.

It is even more commonly used together with the &= operator. For example x &= ~y means to clear the bits in x that are set in y. In this case, it's is more readable to write, for example x &= ~0x40 rather than x &= 0xFC.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top