Програмлю Arduino и читаю в интернете про PORT. Говорят, что какая-то там стабильность будет, если писать вместо =
- |=
, или &=
.
Так я так и не понял, для чего так писать и чем это отличается от обычного "равно"?
Вот пример рабочего кода:
int main() {
DDRB = B00100000;
while(1) {
PORTB |= B00100000;
delay(1000);
PORTB &= B00000000;
delay(1000);
}
}
Если заменить все эти |=
, и &=
на =
, то всё будет работать точно также (как мне кажется) и даже не изменится размер прошивки (скетча). Так возвращаемся к вопросу: Зачем "|=", "&=" и т.д. в c++?
Если вопрос касается именно c++
- то это операторы.
|=
- побитовое или с присвоением.
&=
- побитовое и с присвоением.
Подробнее про операторы тут
По сути, это упрощенный синтаксис для подобной записи:
a = a | b; // для |=
a = a & b; // для &=
Думаю, стало немного яснее, при чем тут равно. Далее попробуем разобраться, для чего же сами операторы |
и &
. Они называются побитовое или и побитовое и соответственно.
Оператор |
берет побитовое представление операндов, и в результате выполнения этого оператора вы получите число, побитовое представление которого будет содержать единицы на тех позициях, на которых хоть в одном из двух побитовых представлений операндов стояла единица. Например:
4 | 5 = 5;
// или (в побитовом представлении)
100 | 101 = 101;
Заметим, что крайняя слева и справа единицы есть хоть в одном из двоичных представлений чисел, и поэтому после выполнения побитового или у нас есть число 101
(в бинарном представлении) или 5
(в десятичной системе счисления).
Оператор &
берет побитовое представления операндов, и в результате выполнения этого оператора вы получите число, побитовое представление которого будет содержать единицы на тех позициях, на которых в обоих побитовых представлениях операндов стояли единицы. Например:
4 & 5 = 4;
// или (в побитовом представлении)
100 | 101 = 100;
Заметим, что осталась лишь одна единица, которая есть и в первом, и в правом операнде.
Ну и совсем вплотную подойдя к вашей задаче - |
и &
применяются обычно для работы с побитовыми флагами. Это сделано для экономии места. К примеру, у вас есть переменная размером 4 байта или 32 бита. В таком случае в этой переменной можно хранить аж 32
флага.
Чтобы добавить флаг, нужно применить |
:
int flags = 0;
// Добавим флаг на третьей справа позиции, ведь бинарное представление 4 - 100
flags |= 0x4;
Чтобы проверить, есть ли флаг, нужно применить &
:
// Бинарное и - по сути маска. И если на этой позиции была 1,
// то результат будет отличен от 0 и условие будет верным
if (flags & 0x4) {
// сделать что-то
}
Как-то так. Почему же работает с равно? Все просто. С равно вы по сути стираете предыдущее состояние переменной с флагами, и передаете ей только 1 флаг вместе с равно. Надеюсь, понятно объяснил...
UPD кстати, в вашем случае PORTB |= B00100000;
добавляет флаг, а потом PORTB &= B00000000;
убирает его (что логично, ведь на той позиции, на которой мы поставили флаг, в B00000000
единицы нет, и применив и мы по сути убрали флажок).
UPD2 кстати, в чистом c++
нет литералов вида B00000000
, это фишка компилятора arduino
. В c++
начиная с версии 14
можно использовать запись вида 0b00000000
, чтобы представить бинарный литерал.
В конкретном вашем коде - да, это все равно. Потому что вам нужо, чтобы вся переменная получала то или иное значение.
Но при программировании всяких - особенно вот таких - вещей это очень нужные операции.
Представьте себе, что ваш PORTB
отвечает сразу за 8 светодиодов. И вам нужно, не меняя остальные - которые светятся, пусть светятся, которые нет - так и остаются - помигать третьим.
Пусть PORTB
был, ну, скажем, B10011010
- четыре светодиода включены
В вашем варианте при присвоении
PORTB = B00000100
вы погасите их все, включив третий. Затем все выключите
PORTB = B00000000
А вот если сделать так:
PORTB = PORTB | B00000100
а затем
PORTB = PORTB & ~B00000100
переменная получит значения B10011110
, а затем опять станет B10011010
. Т.е. вы таким образом способны работать с отдельными битами.
Ну, а запись
PORTB = PORTB | B00000100
немного короче записывается как
PORTB |= B00000100
а
PORTB = PORTB & ~B00000100
как
PORTB &= ~B00000100
Если и это непонятно, то уж не знаю, что и делать...
Если заменить все эти |=, и &= на =, то всё будет работать точно также
Ничего подобного:
auto x{0x0E};
x &= 0x01;
assert(0 == x);
auto y{0x0E};
y = 0x01;
assert(0x01 == y);
Заменить на равно можно, но с применением битового оператора:
auto z{0x0E};
z = z & 0x01;
assert(0x00 == z);
Я хотел бы добавить к ранее сказанным простой пример. Есть массив чисел, но не числа мне нужны, а нужен результат: В какой позиции нечетные числа?
int n[] = {1, 12, 33, 44, 5};
for (int i = 0; i < 5; ++i) {
n[i] &= 1; // нечетным элементам присваиваем 1
}
1
, а четным !1,
т.е. 0
&=
использовать |=
, тогда всем нечетным
числам прибавится 1
, и будет массив выглядеть так 1, 13, 33, 45, 5
Всем здравствуйтеС помощью текстового редактора Блокнот создать файл
Что происходит c TCP-соединением при истечении таймаута SO_KEEPALIVE?
Доброго времени суток, возникла проблема с освобождением памятиВесь код цельный копипастить не буду,вот элементарная часть в которой уже...