Czasem zdarza się jednak, że przekazane kombinacje mogą być bardzo finezyjne, a parametry dla instrukcji warunkowych niekoniecznie muszą mieścić się na jednym ekranie (nazwy flag często są dość długie). W takiej sytuacji idealnym wyjściem byłoby przypisanie wyniku sumy bitowej każdej flagi do osobnej zmiennej typu bool i na niej wykonywać operacje warunkowe. Nie ma jednak nic za darmo. W najbardziej pesymistycznym przypadku będziemy musieli stworzyć 32 lub 64 takie zmienne i dla każdej z nich dokonać przypisania. Narzut jest dość spory. Można to rozwiązać lepiej? Można. Z pomocą przychodzą pola bitowe.
Struktura Data przechowuje pola bitowe. Każde pole zajmuje jeden bit. Ich kolejność jest zgodna z flagami enuma Flags. Dzięki przypisaniu zmiennej przechowującej flagi (uFlags) do owej struktury typu Data (f = *((Data*)&uFlags);), możemy w szybki sposób zacząć pracować z flagami bitowymi, tak samo jak ze zwykłymi zmiennymi typu logicznego.#includestruct Data { bool a : 1; bool b : 1; bool c : 1; }; enum Flags { FLAG_1 = 0x1, FLAG_2 = 0x2, FLAG_3 = 0x4 }; int main() { unsigned int uFlags = FLAG_1 | FLAG_3; Data f; f = *((Data*)&uFlags); printf("%s\n", f.a == true ? "a == true" : "a == false"); printf("%s\n", f.b == true ? "b == true" : "b == false"); printf("%s\n", f.c == true ? "c == true" : "c == false"); return 0; }
Zamiast brzydkiego rzutowania można tę strukturę zapakować w unię z pojedynczym unsigned int - wtedy zwykłe przypisanie wystarczy, a mamy dodatkową kontrolę typów (warning przy automatycznej konwersji typów).
OdpowiedzUsuńunion Data {
unsigned int Flags;
struct {
bool a : 1;
bool b : 1;
bool c : 1;
};
};
// use:
Data d;
d.Flags = uFlags;
Świetny pomysł!
OdpowiedzUsuń