Bitwise-OR vs Adicionando sinalizadores

16

Já vi outras pessoas usando o Bitwise-OR para combinar sinalizadores antes:

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

const byte madPerson = RUN | JUMP | SHOOT;

Também é assim que eu faço.

Mas também vi alguns (não tantos) combinar bandeiras usando a adição:

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

const byte madPerson = RUN + JUMP + SHOOT;

Qual é mais "legível"? (Qual você acha que mais pessoas reconhecerão?) Qual é a maneira "padrão" de fazer isso? Qual você prefere?

Mateen Ulhaq
fonte
Esta é uma pergunta SO. Considere o uso de algo como 1<<0, 1<<1, 1<<2e assim por diante. Quando você tem muitos sinalizadores, ele se torna mais legível, mais sustentável e menos propenso a erros. Por exemplo, se você estiver compactando todos os 64 bits de um int de 64 bits, você realmente deseja evitar erros de digitação :) Como você representa 1também é importante. Para um número inteiro de 64 bits no VS2010, acho que é 1UI64, ou algo assim. Usar um tipo errado pode morder você.
Job
3
@Job: Não é uma pergunta do StackOverflow, porque está perguntando sobre legibilidade, capacidade de reconhecimento, preferências e práticas recomendadas. Nenhuma resposta objetiva para isso; pertence aqui.
precisa

Respostas:

34

OR bit a bit.

A adição é perigosa.

Considere um exemplo em que um bandido é uma pessoa e um bandido zangado é um bandido que fala e atira. Mais tarde, você decide que todos os bandidos devem atirar, mas esqueceu a definição de bandido irritado e não remove sua bandeira de tiro.

#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

Se você usou angryBandit_add o jogo, agora teria o erro lógico desconcertante de ter bandidos raivosos que não podem atirar ou ser mortos.

Se você usasse angryBandit_oro pior, teria um redundante | SHOOTS.

Por razões semelhantes, NOT bit a bit é mais seguro que a subtração para remover sinalizadores.

doppelgreener
fonte
11

OR bit a bit transmite a intenção mais claramente

Além disso, OR bit a bit deve ser mais eficiente

Steven A. Lowe
fonte
De fato, +1 também acho que OR deixa mais claro que esses são sinalizadores, mas no que diz respeito à eficiência, existem idiomas em que as operações bit a bit são lentas, por exemplo, JavaScript all Numbers são 64 flutuadores bit a bit que os operadores precisam fazer conversão implícita nessas.
Ivo Wetzel
1
Dado o exemplo do OP, não acho que uma linha de ORs ou acréscimos impactará negativamente a velocidade de execução de um programa.
the Tin Man
1
@ Greg: especialmente porque o cálculo nesse exemplo será feito em tempo de compilação. :-)
Carson63000
Além de transmitir a intenção é bastante comum ver isso em muitos idiomas, incluindo mas não limitado a ADA, C #, Java ...
Ken Henderson
2
"should" é uma palavra muito grande nesse negócio. Embora seja altamente improvável que você encontre esse problema hoje, tenho lembranças muito claras de trabalhar em um processador que não tinha uma instrução OR bit a bit. Você poderia bit a bit-AND em um instructn e bit a bit-XOR em uma instrução, mas bit a bit-OR tomaria dois: um bit a bit imediato-AND para desativar o bit e um bit a bit imediato-XOR para complementar o bit recém-limpo , que é claro que o definiu.
John R. Strohm