Програмлю 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Сборка персонального компьютера от Artline: умный выбор для современных пользователей