Why use "|=","&=", etc. in C++ instead of"="?
I program Arduino and read about PORT on the Internet. They say that there will be some stability if you write instead of =
- |=
, or &=
.
So I did not understand why to write this way and how it differs from the usual"equal"?
Here is an example of working code:
int main() {
DDRB = B00100000;
while(1) {
PORTB |= B00100000;
delay(1000);
PORTB &= B00000000;
delay(1000);
}
}
If you replace all these |=
, and &=
with =
, then everything will work exactly the same (as it seems to me) and the size of the firmware (sketch) will not even change. So back to the question: Why "|=", "& = " and etc. in c++?
4 answers
If the question concerns exactly c++
, then these are operators.
|=
- bitwise or with assignment.
&=
- bitwise and with assignment.
Learn more about the operators here
In fact, this is a simplified syntax for such a record:
a = a | b; // для |=
a = a & b; // для &=
I think it's a little clearer what equals has to do with it. Next, let's try to figure out what the |
and &
operators themselves are for. They are called bitwise or and bitwise and accordingly.
The |
operator takes the bitwise representation of the operands, and as a result of executing this operator, you will get a number whose bitwise representation will contain units at those positions, on which at least one of the two bitwise representations of the operands had a unit. For example:
4 | 5 = 5;
// или (в побитовом представлении)
100 | 101 = 101;
Note that the leftmost and rightmost units are present in at least one of the binary representations of numbers, and so after executing the bitwise or, we have a number 101
(in binary) or 5
(in decimal).
The &
operator takes the bitwise representation of the operands, and as a result of executing this operator, you will get a number whose bitwise representation will contain units at those positions, on which both bitwise representations of the operands had units. For example:
4 & 5 = 4;
// или (в побитовом представлении)
100 | 101 = 100;
Note that there is only one unit left, which is in both the first and right operands.
Well and coming very close to your task - |
and &
are usually used for working with bitwise flags. This is done to save space. For example, you have a variable of 4 bytes or 32 bits. In this case, you can store as many as 32
flags in this variable.
To add a flag, apply |
:
int flags = 0;
// Добавим флаг на третьей справа позиции, ведь бинарное представление 4 - 100
flags |= 0x4;
To check if there is a flag, you need to apply &
:
// Бинарное и - по сути маска. И если на этой позиции была 1,
// то результат будет отличен от 0 и условие будет верным
if (flags & 0x4) {
// сделать что-то
}
Something like that. Why does it work with equals? It's simple. With equal you are essentially erase the previous state of the variable with flags, and pass it only 1 flag along with equal. I hope you explained it clearly...
UPD by the way, in your case PORTB |= B00100000;
adds a flag, and then PORTB &= B00000000;
removes it (which is logical, because at the position where we put the flag, there is no unit in B00000000
, and by applying and we essentially removed the flag).
UPD2 by the way, in pure c++
there are no literals of the form B00000000
, this is a trick of the compiler arduino
. In c++
starting from versions of 14
can use an entry of the form 0b00000000
to represent a binary literal.
In your specific code-yes, it doesn't matter. Because you need for the entire variable to get one or another value.
But when programming all sorts of things - especially such things-these are very necessary operations.
Imagine that your PORTB
is responsible for 8 LEDs at once. And you need, without changing the rest-which are glowing, let them glow, which are not-and remain-blink the third.
Let PORTB
be, well, say, B10011010
- four LEDs are on
In your version, when assigning
PORTB = B00000100
You will extinguish them all by turning on the third one. Then turn everything off
PORTB = B00000000
But if you do this:
PORTB = PORTB | B00000100
And then
PORTB = PORTB & ~B00000100
The variable will get the values B10011110
, and then become B10011010
again. That is, you are thus able to work with individual bits.
Well, and the entry
PORTB = PORTB | B00000100
A little shorter is written as
PORTB |= B00000100
A
PORTB = PORTB & ~B00000100
As
PORTB &= ~B00000100
If this is not clear, then I do not know what to do...
If you replace all these |=, and &= with =, then everything will work exactly the same
Nothing like this:
auto x{0x0E};
x &= 0x01;
assert(0 == x);
auto y{0x0E};
y = 0x01;
assert(0x01 == y);
You can replace it with equal, but with the use of the bit operator:
auto z{0x0E};
z = z & 0x01;
assert(0x00 == z);
I would like to add a simple example to the above. There is an array of numbers, but I don't need numbers, but I need the result: In what position are the odd numbers?
int n[] = {1, 12, 33, 44, 5};
for (int i = 0; i < 5; ++i) {
n[i] &= 1; // нечетным элементам присваиваем 1
}
- Then the odd ones will be assigned
1
, and the even ones!1,
i.e.0
- And if you use
|=
instead of the&=
operator, then1
will be added to all odd numbers, and the array will look like1, 13, 33, 45, 5
- If you just assign, then all the elements will be units (of course) ...