2010-09-04 12 views
8

Niedawno natknąłem się na kilka przykładów "flag" w C i C++, i nie do końca rozumiem, jak działają. Po patrząc na niektóre kodu źródłowego Zauważyłem, że często wartości flagi są zdefiniowane w systemie szesnastkowym, takie jak:Jak flagi działają w C?

FLAG1 = 0x00000001, 
FLAG2 = 0x00000010, 

Moje intuicyjny sugeruje, że wartości te są łączone. Czy flagi działają, łącząc wszystkie wartości flag w jeden int? Gdybym użył obu tych metod, takich jak FLAG1 | FLAG2, wynik byłby następujący: 0x00000011?

Czy muszę tworzyć teksty stałe z przesunięciami bitowymi czy mogę użyć rosnąco całkowitymi odczuwalna:

FLAG1 = 1; 
FLAG2 = 2; 

Odpowiedz

20

Musisz przesunąć bity, w przeciwnym razie nie ma sposobu na wyodrębnienie poszczególnych flag. Jeśli masz flagi odpowiadające 1, 2, 3, & 4 i łącznej wartości 5, jak możesz stwierdzić, czy było to 2 & 3 lub 1 & 4?

Można również zrobić to w ten sposób, na przykład:

enum { 
    FIRST = 1 << 0, // same as 1 
    SECOND = 1 << 1, // same as 2, binary 10 
    THIRD = 1 << 2, // same as 4, binary 100 
    FOURTH = 1 << 3 // same as 8, binary 1000 
}; 

Następnie połączyć flagi tak:

int flags = FIRST | THIRD | FOURTH; 

I wyodrębnić je tak:

if (flags & THIRD) { ... 
+0

Dziękuję, że to bardzo proste, wygrywasz. –

+3

* wygrywasz * - Naprawdę? Jeśli zostanie opublikowana dobra odpowiedź, powiedziałbym, że ** wszyscy wygrywają. I * naprawdę * mam nadzieję, że PIERWSZY, DRUGI itd. Są po prostu złymi przykładowymi imionami, a nie sugestią, aby ogłosić te stałe raz i ponownie je wykorzystać. 'x = SECOND | CZWARTE 'nie jest tak czytelne jak' x = TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_TRILINEAR'. –

+1

"Wygrywasz" jak w "dziękuję" "wspaniała odpowiedź", akceptuję twoje ". Myślę, że nazywanie było dorozumiane. –

6

Twoja pierwsza metoda nie wykorzystuje bity w najbardziej efektywny sposób. W pierwszym przykładzie używasz notacji szesnastkowej i jest równoznaczne z:

TEXTUREFLAGS_POINTSAMPLE = 1, 
TEXTUREFLAGS_TRILINEAR = 16, 

w drugiej metody wydaje się, że jesteś po prostu zwiększenie o jeden za każdym razem. To nie zadziała po połączeniu flag, ponieważ łączna wartość może być taka sama jak innej flagi (na przykład 1 | 2 == 3).

Należy użyć tych wartości zamiast:

0x00000001 // == 1 
0x00000002 // == 2 
0x00000004 // == 4 
0x00000008 // == 8 
0x00000010 // == 16 
0x00000020 // == 32 
0x00000040 // == 64 
etc... 

Są dwie moce i mogą być łączone za pomocą bitowego albo w jakikolwiek sposób bez podania kolizji.

+0

OK, ale to nie zadziała, jeśli po prostu wykonam jeden, aby polubić 20, prawda? Nadal muszę zachowywać się szesnastkowo, żeby nie nadpisywać siebie nawzajem, prawda? Czy nie rozumiem, jak to działa. –

+1

@ user425756, jeśli nie korzystasz z uprawnień dwóch, nie możesz określić różnicy między ustawianymi 1 i 2 lub ustawionymi wartościami 3. –

+0

Tak, właśnie o tym myślałem. –

4

Takie flagi są wartościami binarnymi, więc możesz łączyć 1, 2, 4, 8, 16, 32, 64, 128 w pojedynczym bajcie lub kolejne moce od 2 do 2^31 i n int. Ponieważ są to wartości binarne, możesz je "lub" połączyć, więc jeśli "lub" razem 1,2,4 skończysz z 7, na przykład. I możesz wyodrębnić bit, który chcesz, używając "i" - więc jeśli masz int z niektórymi flagami lub razem, i chcesz sprawdzić, czy bit "4" jest ustawiony, możesz powiedzieć if (flag & 4) i będzie to prawda jeśli ustawiony jest bit "4".

+0

Dziękuję, że ma więcej sensu. –

2

myśleć o flagi jako tablica 32 bitów (wartości logiczne)

Aby włączyć jeden z tych bitów na ciebie lub niego z 1 < < BitIndex (gdzie BitIndex jest od zera, więc 0 - 31) aby włączyć jeden od ciebie i to z ~ (1 < < BitIndex) aby sprawdzić, czy jest on lub off ty i to z (1 < < BitIndex)

Gdy pojawi się nad różnicą między cyfrowe i/lub przeciwko logiczne OR/AND to wszystko kliknie. Wtedy docenisz notację szesnastkową!