2011-02-07 11 views
5

Rozumiem, że możliwe jest użycie bitmask w wartościach wyliczeniowych, ale nie wiem, jak ją utworzyć.Łączenie wartości wyliczeniowej przy użyciu maski bitowej

Mam proste ENUM:

enum State 
{ 
    minimizing = 0, 
    maximizing, 

    minimized, 
    maximized 
}; 

państwa jest zawsze State.minimized lub State.maximized i może mieć dodatkowe stan na zmiany rozmiaru. Więc coś można zmaksymalizować i zminimalizować

Odpowiedz

16

Zamierzam założyć, że myState ma typ twojego enum State.

Tradycyjne użycie enum polega na tworzeniu stałych wartości, które może przyjmować zmienna tego typu. Chcesz ustawić zmienną myState dla wartości zdefiniowanych w enum.

Parametr enum definiuje 1, 2, 4 i 8 jako prawidłowe wartości, ale użytkownik chce mieć możliwość ustawienia zmiennej na 4 | 2 = 6. Podczas gdy C używa zdefiniowanego przez implementację typu int dla wszystkich enum, nie ma to miejsca w C++. myState = 6 nie jest poprawne w C++. W rzeczywistości myState = 4 nie jest poprawne w C++, musisz rzucić bezpośrednio lub użyć jednej ze stałych nazw enum.

Mimo że jest to możliwe w C, nie jest dobrą praktyką, aby ustawić myState na wartość, która nie jest zdefiniowana przez jego typ (na przykład do 6).

W twoim przypadku, to rozwiązanie, które wydaje konsekwencji byłoby:

typedef enum { 
    OTHER, 
    MINIMIZED, 
    MAXIMIZED 
} win_size_t; 

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

state_t myState; 

W ten sposób, można napisać do pól current i next undependently.

Jeśli nadal chcesz mieć pola bitowe, możesz ustawić rozmiar elementów swojej struktury w bitach. Jest to jednak trochę niebezpieczne, implementacja pól bitowych zależy od twojego kompilatora. Nie jestem nawet pewien, czy kompilatory zaakceptowałyby typ wyliczeniowy w polu bitowym (powinno być w porządku w C, ponieważ enum s są).

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

Poprzednie rozwiązania są oczywiście ważne.Chodzi mi o to, że jeśli twoja zmienna myState ma twój enum State jako typ, powinna używać tylko członków enum dla swoich wartości, a nie dla kombinacji.

Być może myState ma inny typ, co wiem.


Jeśli myState nie jest typu enum State, wówczas można użyć stałych zdefiniowanych w enum w połączeniu.

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 

To pozwala zrobić dwie rzeczy w jednym Zadanie:

myState = MAXIMIZED | MINIMIZING; 

ale również rzeczy, które nie mogą chcieć:

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

dzięki! Poszedłem do opcji nr 1. Rzeczywiście nie ma sensu, który "MAKSYMALIZOWANO | MINIMIZOWANE "jest możliwe, a dla czytelności lepiej mieć dwie wyliczenia. –

+0

Należy pamiętać, że ograniczanie wyliczeń do plików bitowych jest niezdefiniowanym zachowaniem, a wynik zależy od kompilatora. Proszę też poprawić mnie, jeśli się mylę. –

+0

@ DavidTóth Wydajesz się być poprawny, dzięki za to! https://stackoverflow.com/a/33590935/108802 – Gauthier

2

Możesz uzyskać ten efekt, określając wszystkie pola w wyliczeniu i zwiększając moce dwóch, aby uzyskać efekt maski bitowej. Na przykład, w przypadku:

enum State 
{ 
    minimizing = 1, 
    maximizing = 2, 

    minimized = 4, 
    maximized = 8 
}; 

Więc może wtedy mieć swoje kombinacje (State.maximized | State.minimizing). Nie będzie to jednak miało zastosowania wyłącznie do bycia State.maximized lub State.minimized. Jeśli chcesz to zrobić, możesz przekonwertować je na pojedynczy bit, ale wyobrażam sobie, że w tym przykładzie chciałbyś mieć możliwość, w której nie jest to ani zmaksymalizowane, ani zminimalizowane.

+2

która jest zwykle napisana przy użyciu przesunięć – justin

+0

, ale jak mogę z tego korzystać? Jak mam: 'myState = zminimalizowane; if (isMaximizing) {myState = maximizing} 'Chcę ustawić stan maksymalizacji, bez utraty stanu zminimalizowanego. –

+0

Następnie możesz użyć' myState | = maximizing; '. To ustawia bit, który cię interesuje, bez dotykania innych bitów. Aby zerować, użyj 'myState & = ~ maximizing;'. Bądź ostrożny podczas porównań, 'myState == minimized' nie zadziała, potrzebujesz' (myState & minimized) == minised' (lub '! = 0'). Gdybym był tobą, rozważałbym strukturę z jednym polem jako "stanem bieżącym" i innym dla "następnego stanu". – Gauthier

12

Użyj innego bitu dla każdej wartości w swoim wyliczeniu, takich jak:

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

Następnie można połączyć wiele wartości z bitowym OR (minimizing | maximized) i test dla wartości z bitowe oraz (bool is_minimized = (flags & minimized);).

+2

Pytanie o smak, ale ja wolę: '(1u << 0)', '(1u << 1)', '(1u << 2)', '(1u << 3)'. Jest bardziej jasne, o co ci chodzi. – Gauthier

+0

Po co definiować wartości w notacji szesnastkowej? 'minimising = 1' działa też –

+4

@NatanYellin: tak, ale jeśli chcesz dodać jeszcze jeden stan i używasz dziesiętnego, musisz napisać 16. Powiedz, że chcesz ustawić dwa bity, bit 4 i bit 1. Wynik to 18 w systemie dziesiętnym, który jest mniej czytelny niż 0x12 (jeśli nie jest to oczywiste, spróbuj określić, które bity ustawione są w liczbie dziesiętnej 2398. Znacznie łatwiej, jeśli masz odpowiednik 0x95E). Jeśli interesuje cię, które bity są ustawione, szesnastkowo jest drogą do zrobienia. – Gauthier

2

Właśnie próbowałem w VS2012, Optymalizator wydaje się poprawnie łączyć bity bez potrzeby pomocy, jeśli używasz bitfieldów.

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

następnie

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

Zestawy oba bity z jednej instrukcji.

Powiązane problemy