Побитовое ИЛИ против добавления флагов


16

Я видел, как другие использовали Bitwise-OR для объединения флагов раньше:

#define RUN 0x01
#define JUMP 0x02
#define SHOOT 0x04

const byte madPerson = RUN | JUMP | SHOOT;

Я тоже так делаю.

Но я также видел некоторые (не так много) флаги объединения, используя сложение:

#define RUN 0x01
#define JUMP 0x02
#define SHOOT 0x04

const byte madPerson = RUN + JUMP + SHOOT;

Какой из них более «читабелен»? (Как вы думаете, какой из них узнает больше людей?) Каков «стандартный» способ сделать это? Какой из них вы предпочитаете?


Это ТАК вопрос. Рассмотрим , используя нечто вроде 1<<0, 1<<1, 1<<2и так далее. Когда у вас много флагов, он становится более читабельным, более легким в обслуживании, менее подверженным ошибкам. Например, если вы упаковываете все 64 бита 64-битного целого, вы действительно хотите избежать опечаток :) То, как вы представляете 1, также важно. Для 64-разрядного целого числа в VS2010 я думаю, что-то 1UI64, или что-то в этом роде. Использование неправильного типа может укусить вас.
Работа

3
@Job: не вопрос StackOverflow, потому что он спрашивает о читабельности, узнаваемости, предпочтениях и лучших практиках. Нет единого объективного ответа на это; это принадлежит здесь.
Макнейл

Ответы:


34

Побитовое ИЛИ.

Дополнение опасно.

Рассмотрим пример, где бандит - это человек, а злой бандит - это бандит, который говорит и стреляет. Позже вы решаете, что все бандиты должны стрелять, но вы забыли определение злого бандита и не снимаете флаг стрельбы.

#define PERSON 1 << 0
#define SPEAKS 1 << 1
#define SHOOTS 1 << 2
#define INVINCIBLE 1 << 3
const byte bandit = PERSON | SHOOTS;                    // 00000101
const byte angryBandit_add = bandit + SPEAKS + SHOOTS;  // 00001011 error
const byte angryBandit_or = bandit | SPEAKS | SHOOTS;   // 00000111 ok

Если бы вы использовали angryBandit_addсвою игру, то теперь у вас была бы сбивающая с толку логическая ошибка из-за наличия злых бандитов, которые не могут стрелять или быть убиты.

Если бы вы использовали angryBandit_orхудшее, что у вас было бы, это избыточно | SHOOTS.

По тем же причинам побитовое НЕ безопаснее, чем вычитание для удаления флагов.


11

побитовое ИЛИ передает намерение более четко

также побитовое ИЛИ должно быть более эффективным


+1 действительно, я также думаю, что OR делает более ясным, что это флаги, но что касается эффективности, то есть языки, в которых побитовые операции выполняются медленно, например, JavaScript, все числа которых равны 64 числам с плавающей запятой, операторы должны выполнять неявное преобразование для них.
Иво Ветцель

1
Учитывая пример OP, я не думаю, что одна строка OR или сложения отрицательно повлияет на скорость выполнения программы.
Железный человек

1
@Greg: тем более что расчет в этом примере будет сделан во время компиляции. :-)
Carson63000

В дополнение к выражению намерений, довольно часто можно увидеть это на многих языках, включая, помимо прочего, ADA, C #, Java ...
Кен Хендерсон,

2
«должен» это очень большое слово в этом бизнесе. Хотя вряд ли вы столкнетесь с этой проблемой сегодня, у меня очень ясные воспоминания о работе над процессором, у которого не было инструкции побитового ИЛИ. Вы можете поразрядно-И в одной инструкции, и вы можете поразрядно-XOR в одной инструкции, но побитово-ИЛИ потребовалось две: немедленное побитовое И для выключения бита и немедленное побитовое XOR для дополнения недавно очищенного бита , что, конечно, установить его.
Джон Р. Штром
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.