Bitwise-OR vs Agregar banderas

16

He visto a otros usar Bitwise-OR para combinar banderas antes:

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

const byte madPerson = RUN | JUMP | SHOOT;

Esa es también la forma en que lo hago.

Pero también he visto algunos (no tantos) combinan banderas usando la suma:

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

const byte madPerson = RUN + JUMP + SHOOT;

¿Cuál es más "legible"? (¿Cuál crees que reconocerán más personas?) ¿Cuál es la forma "estándar" de hacerlo? ¿Cuál prefieres?

Mateen Ulhaq
fuente
Esta es una pregunta SO. Considere el uso de algo así como 1<<0, 1<<1, 1<<2, y así sucesivamente. Cuando tiene muchas banderas, se vuelve más legible, más fácil de mantener y menos propenso a errores. Por ejemplo, si está empacando todos los 64 bits de un int 64 bits, realmente desea evitar errores tipográficos :) La forma en que representa 1también es importante. Para un entero de 64 bits en VS2010, creo que es 1UI64, o algo así. Usar un tipo incorrecto puede morderte.
Trabajo
3
@ Job: no es una pregunta de StackOverflow, porque se trata de legibilidad, reconocimiento, preferencias y mejores prácticas. No hay una respuesta objetiva única para ello; Pertenece aquí.
Macneil

Respuestas:

34

Bitwise-OR.

La adición es peligrosa.

Considere un ejemplo donde un bandido es una persona, y un bandido enojado es un bandido que habla y dispara. Más tarde, decides que todos los bandidos deberían disparar, pero te has olvidado de la definición de bandido enojado y no eliminas su bandera de disparos.

#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

Si usaras angryBandit_addtu juego ahora tendría el error lógico desconcertante de tener bandidos enojados que no pueden disparar o ser asesinados.

Si angryBandit_orusaras lo peor que tendrías es redundante | SHOOTS.

Por razones similares, NO a nivel de bits es más seguro que la resta para eliminar banderas.

doppelgreener
fuente
11

bitwise-OR transmite la intención más claramente

también, bitwise-OR debería ser más eficiente

Steven A. Lowe
fuente
De hecho, también creo que O deja en claro que esos son indicadores, pero con respecto a la eficiencia, hay lenguajes donde las operaciones bit a bit son lentas, por ejemplo, JavaScript todos los números son 64 flotantes, los operadores bit a bit deben realizar una conversión implícita en ellos.
Ivo Wetzel
1
Dado el ejemplo del OP, no creo que una línea de OR o adición vaya a afectar negativamente la velocidad de ejecución de un programa.
The Tin Man
1
@Greg: especialmente porque el cálculo en ese ejemplo se realizará en tiempo de compilación. :-)
Carson63000
Además de transmitir la intención, es bastante común ver esto en muchos idiomas, incluidos, entre otros, ADA, C #, Java ...
Ken Henderson
2
"debería" es una palabra muy importante en este negocio. Si bien es muy poco probable que encuentre este problema hoy, tengo recuerdos muy claros de trabajar en un procesador que no tenía una instrucción OR bit a bit. Podrías bitwise-AND en una instrucción, y podrías bitwise-XOR en una instrucción, pero bitwise-OR tomó dos: un bitwise inmediato-AND para apagar el bit y un bitwise-XOR inmediato para complementar el bit recién borrado , que por supuesto lo estableció.
John R. Strohm