2011-02-07 15 views
5

Entiendo que es posible usar máscaras de bits en valores enum, pero no sé cómo crearlo.Combinando Enum Value usando Bitmask

Tengo una enumeración simple:

enum State 
{ 
    minimizing = 0, 
    maximizing, 

    minimized, 
    maximized 
}; 

Un estado es siempre State.minimized o State.maximized, y puede tener estatal sobre cambio de tamaño. Entonces algo se puede maximizar y minimizar

Respuesta

16

Voy a suponer que myState tiene el tipo de su enum State.

El uso tradicional de enum es crear los valores constantes que una variable de este tipo puede tomar. Desea establecer la variable myState en una combinación de los valores definidos en enum.

El enum define 1, 2, 4 y 8 como valores válidos, pero desea poder establecer la variable en 4 | 2 = 6. Mientras que C usa su tipo int definido por implementación para todos enum, no es el caso en C++. myState = 6 no es válido en C++. En realidad, myState = 4 no es válido en C++, necesita emitir explícitamente o usar uno de los nombres de constante del enum.

Aunque es posible en C, no es una buena práctica establecer myState en un valor que no esté definido por su tipo (por ejemplo, a 6).

En su caso, una solución que parece consecuente sería:

typedef enum { 
    OTHER, 
    MINIMIZED, 
    MAXIMIZED 
} win_size_t; 

typedef struct { 
    win_size_t current; 
    win_size_t next; 
} state_t; 

state_t myState; 

De esta manera, se puede escribir en los campos current y next undependently.

Si aún desea tener campos de bit, puede establecer el tamaño de los elementos de su estructura en bits. Aunque es algo peligroso, la implementación de los campos de bit depende de tu compilador. Ni siquiera estoy seguro de si los compiladores aceptarían tener un tipo de enumeración en un campo de bit (debería estar bien en C, ya que enum s son int).

typedef struct { 
    win_size_t current : 2; // not tested 
    win_size_t next : 2; 
} state_t; 

Las soluciones anteriores son válidas, por supuesto.Mi punto es que si su variable myState tiene su tipo enum State, solo debe usar los miembros de enum para sus valores, no una combinación.

Tal vez myState tiene otro tipo, ¿qué sé yo?


Si myState no es del tipo enum State, entonces puede usar las constantes definidas en su enum en combinación.

enum State { 
    MINIMIZING = (1u << 0), 
    MAXIMIZING = (1u << 1), 
    MINIMIZED = (1u << 2), 
    MAXIMIZED = (1u << 3), 
}; 

unsigned int myState = 0; 

myState |= MAXIMIZED; // sets that bit 
myState &= ~MAXIMIZED; // resets that bit 

Esto le permite hacer dos cosas en una asignación:

myState = MAXIMIZED | MINIMIZING; 

Pero también cosas que no es probable que desee:

myState = MAXIMIZED | MINIMIZED; // does that make sense? 
+0

gracias! Fui por la opción n. ° 1. De hecho, eso no tiene sentido que 'MAXIMIZED | MINIMIZED' es posible, y es mejor para la legibilidad tener dos enumeraciones. –

+0

Tenga en cuenta que restringir las enumeraciones a los archivos de bits es un comportamiento indefinido y el resultado depende del compilador. También por favor corrígeme si estoy equivocado. –

+0

@ DavidTóth Parece que tienes razón, ¡gracias por esto! https://stackoverflow.com/a/33590935/108802 – Gauthier

2

Puede obtener este efecto especificando todos los campos en la enumeración y aumentando en potencias de dos para obtener el efecto de máscara de bits. Por ejemplo, en su caso:

enum State 
{ 
    minimizing = 1, 
    maximizing = 2, 

    minimized = 4, 
    maximized = 8 
}; 

modo que lo pueda tener sus combinaciones de (State.maximized | State.minimizing). Sin embargo, esto no aplicará la restricción de solo ser State.maximized o State.minimized. Si quieres hacer eso, podrías convertirlos a un solo bit, pero imagino que en este ejemplo querrás tener un caso en el que no se maximice ni se minimice.

+2

que generalmente se escribe usando los turnos – justin

+0

pero entonces, ¿cómo puedo usarlo? Como tengo: 'myState = minimized; if (isMaximizing) {myState = maximizing} 'Quiero establecer el estado de maximización, sin perder el estado minimizado –

+0

Luego puede usar' myState | = maximizing; '. Esto establece el bit en el que estás interesado sin tocar los otros bits. Para la puesta a cero, use 'myState & = ~ maximizing;'. Tenga cuidado al hacer comparaciones, 'myState == minimized' no funcionará, necesitaría' (myState & minimized) == minimized' (o '! = 0'). Si yo fuera usted, consideraría una estructura con un campo como "estado actual" y otra para "próximo estado". – Gauthier

12

utilizar un poco diferente para cada valor en su enumeración, tales como:

enum State 
{ 
    minimizing = 0x01, // 00000001 
    maximizing = 0x02, // 00000010 
    minimized = 0x04, // 00000100 
    maximized = 0x08 // 00001000 
}: 

A continuación, puede combinar varios valores con bit a bit o (minimizing | maximized) y prueba de los valores con bit a bit y (bool is_minimized = (flags & minimized);).

+2

Pregunta de gusto, pero prefiero: '(1u << 0)', '(1u << 1)', '(1u << 2)', '(1u << 3)'. Está más claro a qué se refiere. – Gauthier

+0

¿Por qué definir los valores en notación hexadecimal? 'minimizing = 1' también funciona –

+4

@NatanYellin: lo hace, pero si va a agregar un estado más y está usando decimal, tendría que escribir 16. Digamos que desea establecer dos bits, bit 4 y bit 1. El resultado es 18 en decimal, que es menos legible que 0x12 (si esto no es obvio, intente identificar qué bits se establecen en decimal 2398. Mucho más fácil si tiene el equivalente 0x95E). Si está interesado en qué bits se establecen, hexadecimal es el camino a seguir. – Gauthier

2

simplemente he intentado esto en VS2012, la el optimizador parece combinar bits correctamente sin necesidad de asistencia si está utilizando bitfields.

struct BITS { int x: 1; int y:1; }; 

continuación

BITS b; 
b.x = b.y = 1; 

conjuntos de los dos bits con una instrucción.