#cpp #операторы
Програмлю Arduino и читаю в интернете про PORT. Говорят, что какая-то там стабильность
будет, если писать вместо = - |=, или &=.
Так я так и не понял, для чего так писать и чем это отличается от обычного "равно"?
Вот пример рабочего кода:
int main() {
DDRB = B00100000;
while(1) {
PORTB |= B00100000;
delay(1000);
PORTB &= B00000000;
delay(1000);
}
}
Если заменить все эти |=, и &= на =, то всё будет работать точно также (как мне кажется)
и даже не изменится размер прошивки (скетча). Так возвращаемся к вопросу: Зачем "|=",
"&=" и т.д. в c++?
Ответы
Ответ 1
Если вопрос касается именно 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, чтобы представить бинарный литерал.Ответ 2
В конкретном вашем коде - да, это все равно. Потому что вам нужо, чтобы вся переменная получала то или иное значение. Но при программировании всяких - особенно вот таких - вещей это очень нужные операции. Представьте себе, что ваш 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 Если и это непонятно, то уж не знаю, что и делать...Ответ 3
Если заменить все эти |=, и &= на =, то всё будет работать точно также Ничего подобного: 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);Ответ 4
Я хотел бы добавить к ранее сказанным простой пример. Есть массив чисел, но не числа мне нужны, а нужен результат: В какой позиции нечетные числа? 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 Если же просто присвоить, тогда все элементы будут единицами (естественно)...
Комментариев нет:
Отправить комментарий