2010-09-04 23 views
8

Récemment, j'ai rencontré plusieurs exemples de "drapeaux" en C et C++, et je ne comprends pas très bien comment ils fonctionnent. Après avoir regardé un code source, j'ai remarqué que, souvent, les valeurs de drapeau sont définies en hexadécimal telles que les suivantes:Comment les drapeaux fonctionnent-ils en C?

FLAG1 = 0x00000001, 
FLAG2 = 0x00000010, 

Mon intuition suggère que ces valeurs sont combinées. Est-ce que les drapeaux fonctionnent en combinant toutes les valeurs de drapeaux dans un int? Si j'avais utilisé les deux comme FLAG1 | FLAG2, le résultat serait-il 0x00000011?

Ai-je besoin de créer énumérations avec des décalages de bits ou puis-je utiliser des entiers croissant comme:

FLAG1 = 1; 
FLAG2 = 2; 

Répondre

20

Vous devez décaler les bits, sinon il n'y a aucun moyen d'extraire les drapeaux individuels. Si vous aviez des drapeaux correspondant à 1, 2, 3, & 4, et une valeur combinée de 5, comment pourriez-vous dire si c'était 2 & 3 ou 1 & 4?

Vous pouvez aussi le faire de cette façon, par exemple:

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 
}; 

Ensuite, vous combinez des drapeaux comme ceci:

int flags = FIRST | THIRD | FOURTH; 

Et vous les extraire comme ceci:

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

Merci, c'est très simple, vous gagnez. –

+3

* vous gagnez * - Vraiment? Si une bonne réponse est affichée, je dirais que ** tout le monde ** gagne. Et j'espère vraiment que FIRST, SECOND, etc. ne sont que de mauvais exemples et ne suggèrent pas de les déclarer une seule fois et de les réutiliser. 'x = SECOND | FOURTH' n'est pas aussi lisible que 'x = TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_TRILINEAR'. –

+1

"Vous gagnez" comme dans "merci" "bonne réponse," j'accepte le vôtre. "Je pense que la dénomination était implicite –

6

Votre première méthode n'utilise pas les bits de la manière la plus efficace. Dans le premier exemple, vous utilisez la notation hexadécimale et il est équivalent à:

TEXTUREFLAGS_POINTSAMPLE = 1, 
TEXTUREFLAGS_TRILINEAR = 16, 

Dans la deuxième méthode, il semble que vous êtes juste incrémentant d'une à chaque fois. Cela ne fonctionnera pas lorsque vous combinez des indicateurs, car la valeur combinée peut être identique à un autre indicateur (par exemple, 1 | 2 == 3).

Vous devez utiliser ces valeurs à la place:

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

Ce sont les puissances de deux et ils peuvent être combinés en utilisant ou en bitwise quelque manière que ce sans donner des collisions.

+0

Ok mais ça ne marchera pas si je fais juste un pour aimer 20 ça? Je dois encore échelonner l'hexadécimal afin qu'ils ne s'écrasent pas l'un l'autre à droite? Ou je ne comprends pas comment cela fonctionne. –

+1

@ user425756, si vous n'utilisez pas les puissances de deux, vous ne pouvez pas faire la différence entre le 1 et le 2 en train d'être réglés, ou 3 étant réglé. –

+0

Ouais c'est ce que je pensais. –

4

Les drapeaux comme celui-ci sont des valeurs binaires, donc vous pouvez combiner 1, 2, 4, 8, 16, 32, 64, 128 dans un seul octet, ou d'autres puissances de 2 jusqu'à 2^31 i n un int. Parce qu'ils sont des valeurs binaires, vous pouvez les "ou" ensemble, donc si vous "ou" ensemble 1,2,4 vous vous retrouvez avec 7, par exemple. Et vous pouvez extraire le bit que vous voulez en utilisant "et" - donc si vous avez un int avec quelques drapeaux ou ensemble, et vous voulez voir si le bit "4" est mis, vous pouvez dire if (flag & 4) et ce sera vrai si le bit "4" est défini.

+0

Merci qui a plus de sens. –

2

Pensez des drapeaux comme un tableau de 32 bits (booléens)

Pour mettre un de ces bits sur vous ou avec 1 < < BitIndex (où BitIndex est basé à zéro, 0 - 31) pour mettre un hors tension vous et avec ~ (1 < < BitIndex) pour vérifier si elle est ou de vous et avec (1 < < BitIndex)

une fois que vous obtenez sur la différence entre le numérique oU/ET contre logique OU/ET tout va cliquer. Ensuite, vous apprécierez la notation hexadécimale!