Quels sont les cas d'utilisation réels des opérateurs de bits suivants?
Champs de bits (drapeaux)
C’est le moyen le plus efficace de représenter quelque chose dont l’état est défini par plusieurs propriétés "oui ou non". Les ACL sont un bon exemple. Si vous disposez de 4 autorisations discrètes (lecture, écriture, exécution, modification de la politique), il est préférable de la stocker dans 1 octet plutôt que dans la perte 4. Celles-ci peuvent être associées à des types d'énumération dans de nombreuses langues pour plus de commodité.
Communication sur les ports/sockets
Implique toujours les sommes de contrôle, la parité, les bits d’arrêt, les algorithmes de contrôle de flux, etc., qui dépendent généralement des valeurs logiques d’octets individuels et non de valeurs numériques, car le support ne peut transmettre un bit à un temps.
Compression, Cryptage
Ces deux éléments dépendent fortement des algorithmes au niveau des bits. Regardez l'algorithme deflate pour un exemple - tout est en bits, pas en octets.
Machines à états finis
Je parle principalement du type intégré dans certains éléments matériels, même s’ils peuvent également être trouvés dans les logiciels. Celles-ci sont de nature combinatoire - elles pourraient littéralement devenir "compilées" en un tas de portes logiques, elles doivent donc être exprimées sous la forme AND
, OR
, NOT
, etc.
Graphiques Il n’ya guère assez de place ici pour pénétrer dans tous les domaines où ces opérateurs sont utilisés dans la programmation graphique. XOR
(ou ^
) est particulièrement intéressant ici car appliquer la même entrée une seconde fois annulera la première. Les anciennes interfaces graphiques utilisaient cette fonctionnalité pour la mise en surbrillance de la sélection et d’autres superpositions, afin d’éviter le besoin de redessins coûteux. Ils sont toujours utiles dans les protocoles graphiques lents (bureau à distance).
Ce ne sont que les premiers exemples que j'ai cités - ce n'est pas une liste exhaustive.
Est-ce étrange?
(value & 0x1) > 0
Est-ce divisible par deux (pair)?
(value & 0x1) == 0
La programmation de bas niveau est un bon exemple. Par exemple, vous pouvez avoir besoin d'écrire un bit spécifique dans un registre mappé en mémoire pour que le matériel fasse ce que vous voulez:
volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t value;
uint32_t set_bit = 0x00010000;
uint32_t clear_bit = 0x00001000;
value = *register; // get current value from the register
value = value & ~clear_bit; // clear a bit
value = value | set_bit; // set a bit
*register = value; // write it back to the register
De plus, htonl()
et htons()
sont implémentés à l'aide des opérateurs &
Et |
(Sur des machines dont endianness (ordre d'octet ) ne correspond pas à l'ordre du réseau):
#define htons(a) ((((a) & 0xff00) >> 8) | \
(((a) & 0x00ff) << 8))
#define htonl(a) ((((a) & 0xff000000) >> 24) | \
(((a) & 0x00ff0000) >> 8) | \
(((a) & 0x0000ff00) << 8) | \
(((a) & 0x000000ff) << 24))
Voici quelques expressions usuelles concernant les drapeaux stockés sous forme de bits individuels.
enum CDRIndicators {
Local = 1 << 0,
External = 1 << 1,
CallerIDMissing = 1 << 2,
Chargeable = 1 << 3
};
unsigned int flags = 0;
Définir le drapeau facturable:
flags |= Chargeable;
Désactivez l'indicateur CallerIDMissing:
flags &= ~CallerIDMissing;
Vérifiez si les identificateurs CallerIDMissing et Chargeable sont définis:
if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {
}
J'ai utilisé des opérations au niveau des bits pour implémenter un modèle de sécurité pour un CMS. Il y avait des pages auxquelles les utilisateurs pouvaient accéder s'ils se trouvaient dans des groupes appropriés. Un utilisateur peut être dans plusieurs groupes, nous avons donc dû vérifier s'il existait une intersection entre les groupes d'utilisateurs et les groupes de pages. Nous avons donc attribué à chaque groupe un identifiant unique de puissance de 2, par exemple:
Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100
Nous OR ces valeurs ensemble et stockons la valeur (sous la forme d'un seul int) avec la page. Par exemple, si une page peut être accédée par les groupes A & B, nous stockons la valeur 3 (qui dans binaire est 00000011) comme le contrôle d’accès aux pages De la même manière, nous stockons une valeur d’identificateurs de groupe ORed avec un utilisateur pour représenter les groupes dans lesquels il se trouve.
Donc, pour vérifier si un utilisateur donné peut accéder à une page donnée, il vous suffit de combiner ET les valeurs ensemble et de vérifier si la valeur est différente de zéro. Ceci est très rapide car cette vérification est implémentée dans une seule instruction, pas de boucle, pas d'allers-retours de base de données.
Je les utilise pour obtenir des valeurs RVB (A) à partir de valeurs de couleur compactées, par exemple.
Quand j'ai un tas de drapeaux booléens, j'aime les stocker tous dans un int.
Je les sors en utilisant bitwise-AND. Par exemple:
int flags;
if (flags & 0x10) {
// Turn this feature on.
}
if (flags & 0x08) {
// Turn a second feature on.
}
etc.
& = ET:
Masquer des bits spécifiques.
Vous définissez les bits spécifiques qui doivent être affichés ou non. 0x0 & x effacera tous les bits d'un octet tandis que 0xFF ne changera pas x. 0x0F affichera les bits dans le quartet inférieur.
Conversion:
Pour convertir les variables plus courtes en variables plus longues avec une identité de bits, il est nécessaire d'ajuster les bits, car -1 dans un int correspond à 0xFFFFFFFF alors que -1 dans un long correspond à 0xFFFFFFFFFFFFFFFF. Pour préserver l'identité, appliquez un masque après la conversion.
| = OU
Définir les bits. Les bits seront définis indépendamment s'ils sont déjà définis. De nombreuses infrastructures de données (champs de bits) ont des indicateurs tels que IS_HSET = 0, IS_VSET = 1, qui peuvent être définis de manière indépendante. Pour définir les indicateurs, vous appliquez IS_HSET | IS_VSET (En C et Assembly, cela est très pratique à lire)
^ = XOR
Recherchez des bits identiques ou différents.
~ = PAS
Bits Flip.
On peut montrer que toutes les opérations de bits locales possibles peuvent être implémentées par ces opérations. Donc, si vous le souhaitez, vous pouvez implémenter une instruction ADD uniquement par bits.
Quelques hacks merveilleux:
http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html
Le cryptage est une opération bit à bit.
Vous pouvez les utiliser comme un moyen rapide et corrompu de hacher des données.
int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;
Je viens d'utiliser bitwise-XOR (^
) il y a environ trois minutes pour calculer une somme de contrôle pour la communication série avec un automate ...
Ceci est un exemple pour lire les couleurs d'une image bitmap au format octet
byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */
//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */
//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF; /* This now returns a red colour between 0x00 and 0xFF.
J'espère que ces exemples minuscules aident ....
Bitwise & est utilisé pour masquer/extraire une certaine partie d'un octet.
1 octet variable
01110010
&00001111 Bitmask of 0x0F to find out the lower nibble
--------
00000010
En particulier, l'opérateur de décalage (<< >>) est souvent utilisé pour les calculs.
Dans le monde abstrait du langage moderne, pas trop. Fichier IO est un fichier simple qui me vient à l’esprit, bien qu’il s’agisse d’exercer des opérations au niveau des bits sur quelque chose déjà implémenté et qui n’implémente pas quelque chose qui utilise des opérations au niveau des bits. Néanmoins, comme exemple simple, ce code montre la suppression l'attribut en lecture seule d'un fichier (afin qu'il puisse être utilisé avec un nouveau FileStream spécifiant FileMode.Create) en c #:
//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
FileAttributes attributes = File.GetAttributes(targetName);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));
File.Delete(targetName);
}
En ce qui concerne les implémentations personnalisées, voici un exemple récent: j'ai créé un "centre de messagerie" permettant d'envoyer des messages sécurisés d'une installation de notre application distribuée à une autre. Fondamentalement, cela ressemble à un courrier électronique, avec Boîte de réception, Boîte d'envoi, Envoyé, etc., mais la livraison avec accusé de réception est également garantie, de sorte qu'il existe des sous-dossiers supplémentaires au-delà de "boîte de réception" et "envoyé". Ce qui en résultait était une obligation pour moi de définir de manière générique ce qu'il y avait "dans la boîte de réception" ou "dans le dossier envoyé". Dans le dossier envoyé, j'ai besoin de savoir ce qui est lu et ce qui n'est pas lu. De ce qui n'est pas lu, j'ai besoin de savoir ce qui est reçu et ce qui n'a pas été reçu. J'utilise ces informations pour créer une clause where dynamique qui filtre une source de données locale et affiche les informations appropriées.
Voici comment l'énum est mis en place:
public enum MemoView :int
{
InboundMemos = 1, // 0000 0001
InboundMemosForMyOrders = 3, // 0000 0011
SentMemosAll = 16, // 0001 0000
SentMemosNotReceived = 48, // 0011
SentMemosReceivedNotRead = 80, // 0101
SentMemosRead = 144, // 1001
Outbox = 272, //0001 0001 0000
OutBoxErrors = 784 //0011 0001 0000
}
Voyez-vous ce que cela fait? En anding (&) avec la valeur "Enbox" d'énumération, InboundMemos, je sais qu'InboundMemosForMyOrders est dans la boîte de réception.
Voici une version abrégée de la méthode qui génère et retourne le filtre qui définit une vue pour le dossier actuellement sélectionné:
private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
{
string filter = string.Empty;
if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
{
filter = "<inbox filter conditions>";
if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
{
filter += "<my memo filter conditions>";
}
}
else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
{
//all sent items have originating system = to local
filter = "<memos leaving current system>";
if((view & MemoView.Outbox) == MemoView.Outbox)
{
...
}
else
{
//sent sub folders
filter += "<all sent items>";
if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
{
if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
{
filter += "<not received and not read conditions>";
}
else
filter += "<received and not read conditions>";
}
}
}
return filter;
}
Extrêmement simple, mais une mise en œuvre soignée à un niveau d'abstraction qui n'exige généralement pas d'opérations au niveau des bits.
L'encodage Base64 est un exemple. Le codage Base64 est utilisé pour représenter les données binaires en tant que caractères imprimables pour les envois via des systèmes de messagerie (et à d’autres fins). Le codage Base64 convertit une série d'octets de 8 bits en index de recherche de caractères de 6 bits. Les opérations sur les bits, les décalages et les modifications, ou les remarques, sont très utiles pour la mise en oeuvre des opérations sur les bits nécessaires au codage et au décodage en Base64.
Ce n'est bien sûr que l'un des innombrables exemples.
Je suis surpris que personne n'ait choisi la réponse évidente à l'ère d'Internet. Calcul des adresses réseau valides pour un sous-réseau.
Les opérateurs au niveau des bits sont utiles pour boucler des tableaux dont la longueur est égale à la puissance 2. Comme beaucoup de personnes l'ont mentionné, les opérateurs au niveau du bit sont extrêmement utiles et sont utilisés dans Drapeaux, Graphiques, Mise en résea, cryptage. Non seulement cela, mais ils sont extrêmement rapides. Mon utilisation personnelle préférée est de boucler un tableau sans conditionnels . Supposons que vous ayez un tableau à indice zéro (par exemple, l'index du premier élément est 0) et que vous devez le boucler indéfiniment. Par indéfiniment, je veux dire aller du premier élément au dernier et revenir au premier. Une façon d'implémenter ceci est:
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
if (i >= arr.length)
i = 0;
}
C'est l'approche la plus simple, si vous souhaitez éviter l'instruction if, vous pouvez utiliser l'approche module comme suit:
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
i = i % arr.length;
}
L'inconvénient de ces deux méthodes est que l'opérateur de module est coûteux, car il recherche un reste après la division entière. Et la première méthode exécute une instruction if à chaque itération. Avec l'opérateur bit à bit, cependant, si la longueur de votre tableau est une puissance de 2, vous pouvez facilement générer une séquence telle que 0 .. length - 1
En utilisant l'opérateur &
(Bitwise et) comme si i & length
. Sachant cela, le code ci-dessus devient
int[] arr = new int[8];
int i = 0;
while (true){
print(arr[i]);
i = i + 1;
i = i & (arr.length - 1);
}
Voici comment cela fonctionne. Au format binaire , chaque nombre ayant une puissance de 2 soustrait de 1 n'est exprimé qu'avec des uns. Par exemple, 3 en binaire est 11
, 7 est 111
, 15 est 1111
Et ainsi de suite, vous voyez l'idée. Maintenant, que se passe-t-il si vous &
Un nombre contre un nombre composé uniquement de nombres en binaire? Disons que nous faisons ceci:
num & 7;
Si num
est inférieur ou égal à 7, le résultat sera num
car chaque bit &
- associé à 1 est lui-même. Si num
est supérieur à 7, lors de l'opération &
, L'ordinateur prendra en compte les zéros de 7 qui, bien sûr, resteront sous la forme de zéros après l'opération &
, Il ne restera que la dernière partie. Comme dans le cas de 9 & 7
En binaire, cela ressemblera à
1001 & 0111
le résultat sera 0001, ce qui correspond à 1 en décimal et au deuxième élément du tableau.
Personne ne semble avoir mentionné les mathématiques à points fixes.
(Ouais, je suis vieux, d'accord?)
Généralement, les opérations au niveau des bits sont plus rapides que multiplier/diviser. Donc, si vous avez besoin de multiplier une variable x par exemple 9, vous ferez x<<3 + x
, Ce qui serait plus rapide de quelques cycles que x*9
. Si ce code est à l'intérieur d'un ISR, vous gagnerez du temps de réponse.
De même, si vous souhaitez utiliser un tableau en tant que file d'attente circulaire, il sera plus rapide (et plus élégant) de gérer les vérifications en boucle avec des opérations par bits. (la taille de votre tableau doit être une puissance de 2). Par exemple, vous pouvez utiliser tail = ((tail & MASK) + 1)
au lieu de tail = ((tail +1) < size) ? tail+1 : 0
, si vous souhaitez insérer/supprimer.
De même, si vous souhaitez qu'un indicateur d'erreur contienne plusieurs codes d'erreur ensemble, chaque bit peut contenir une valeur distincte. Vous pouvez ET le vérifier avec chaque code d'erreur individuel. Ceci est utilisé dans les codes d'erreur Unix.
Un bitmap n-bit peut également constituer une structure de données compacte et vraiment cool. Si vous souhaitez allouer un pool de ressources de taille n, vous pouvez utiliser un n-bits pour représenter l'état actuel.
Je les utilise pour les options de sélection multiple, ainsi je ne stocke qu'une valeur au lieu de 10 ou plus
il peut également être utile dans un modèle relationnel SQL, supposons que vous ayez les tables suivantes: BlogEntry, BlogCategory
en règle générale, vous pouvez créer une relation nn entre eux à l'aide d'une table BlogEntryCategory ou, lorsqu'il n'y a pas beaucoup d'enregistrements BlogCategory, vous pouvez utiliser une valeur dans BlogEntry pour créer un lien vers plusieurs enregistrements BlogCategory, comme vous le feriez avec des énumérations marquées, dans la plupart des SGBDR. très rapide pour les opérateurs de sélectionner cette colonne "signalée" ...
Lorsque vous ne souhaitez modifier que quelques bits des sorties d'un microcontrôleur, mais que le registre dans lequel vous écrivez est un octet, procédez comme suit (pseudocode):
char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs
Bien sûr, de nombreux microcontrôleurs vous permettent de changer chaque bit individuellement ...
Un nombre x
est-il une puissance de 2? (Utile par exemple dans les algorithmes où un compteur est incrémenté et où une action doit être prise uniquement nombre logarithmique de fois)
(x & (x - 1)) == 0
Quel est le bit le plus élevé d'un entier x
? (Ceci peut par exemple être utilisé pour trouver la puissance minimale de 2 supérieure à x
)
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift
Quel est le plus bas 1
bit d'un entier x
? (Aide à trouver le nombre de fois divisible par 2.)
x & -x
Si vous voulez calculer votre nombre mod (%) avec une certaine puissance de 2, vous pouvez utiliser yourNumber & 2^N-1
, qui dans ce cas est identique à yourNumber % 2^N
.
number % 16 = number & 15;
number % 128 = number & 127;
Ceci n’est probablement utile qu’en tant que solution de rechange au fonctionnement sur module avec un très gros dividende de 2 ^ N ... Mais même dans ce cas, son gain de vitesse par rapport au fonctionnement sur module est négligeable dans mon test sur .NET 2.0. Je pense que les compilateurs modernes effectuent déjà des optimisations comme celle-ci. Quelqu'un en sait-il plus?
La solution linéaire de Tower Of Hanoi utilise des opérations au niveau des bits pour résoudre le problème.
public static void linear(char start, char temp, char end, int discs)
{
int from,to;
for (int i = 1; i < (1 << discs); i++) {
from = (i & i-1) % 3;
to = ((i | i-1) + 1) % 3;
System.out.println(from+" => "+to);
}
}
L'explication de cette solution peut être trouvée ici
Ils sont principalement utilisés pour les opérations au niveau des bits (surprise). Voici quelques exemples concrets trouvés dans PHP codebase.
Encodage de caractère:
if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {
Structures de données:
ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
Pilotes de base de données:
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
Mise en œuvre du compilateur:
opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;
Je ne pense pas que cela compte en bits, mais Ruby's Array définit les opérations définies à l'aide des opérateurs entiers normaux en bits. Alors [1,2,4] & [1,2,3] # => [1,2]
. De même pour a ^ b #=> set difference
et a | b #=> union
.
Je les ai vus utilisés dans des systèmes de contrôle d'accès basés sur des rôles.
Chaque fois que j'ai commencé la programmation en C, j'ai compris les tables de vérité et tout ça, mais tout n'a pas été expliqué avant de lire cet article http://www.gamedev.net/reference/articles /article1563.asp (qui donne des exemples réels)
Il y a une utilisation du monde réel dans ma question ici -
Ne répondez qu'à la première notification WM_KEYDOWN?
Lors de la consommation d'un message WM_KEYDOWN dans la fenêtre C api, le bit 30 spécifie l'état de clé précédent. La valeur est 1 si la clé est enfoncée avant l'envoi du message ou zéro si la clé est active.
Je l'ai vu dans quelques livres de développement de jeux comme un moyen plus efficace de se multiplier et de se diviser.
2 << 3 == 2 * 8
32 >> 4 == 32 / 16
Personne n'a encore mentionné les collections. Parfois, vous avez une petite collection de valeurs possibles, disons seulement 10 ou 20 valeurs possibles, et vous souhaitez conserver certaines d'entre elles dans un ensemble. Bien sûr, vous pouvez utiliser une implémentation régulière de Set
qui utilisera très probablement une hashtable de sauvegarde. Mais comme l'ensemble des valeurs possibles est si petit, il ne s'agit que d'une perte de temps et d'espace. Au lieu de cela, vous pouvez stocker le jeu dans une seule valeur int
ou long
qui correspond exactement à ce que Java EnumSet
si je me souviens bien.
Je les utilise pour mettre en œuvre des calculs rapides de BCD (les comptables et les auditeurs sont mécontents des arrondis fp).
J'ai toujours pensé que les opérations au niveau des bits sont des opérations assez simples. Par conséquent, lorsque le temps d'exécution est crucial, une solution implémentée via des jeux de bits peut améliorer le temps d'exécution d'une quantité constante, en fonction de l'algorithme.
Nous utilisons Bitwise Flags pour rendre la session plus petite pour les autorisations de connexion sur notre site Web interne.
Une utilisation courante est l'alignement. Par exemple, j'ai besoin d'aligner mes données sur des limites de 4 ou 16 octets. C'est très courant avec les processeurs RISC où un chargement/stockage non aligné est coûteux (car il déclenche un gestionnaire d'exceptions qui doit ensuite être corrigé). la charge non alignée) ou pas du tout.
Pour tout alignement de puissance 2, le prochain pos aligné peut être calculé comme suit:
aligned_offset = alignment + ((current_offset - 1) & ~(alignment - 1))
Donc, dans le cas d'un alignement de 4 octets et d'un décalage actuel de 9, alors:
aligned_offset = 4 + ((9-1) & ~(4-1)) = 4 + (8 & 0xFFFFFFFC) = 4+ 8 = 12
donc le décalage suivant de 4 octets serait de 12
J'utilise souvent des opérations au niveau des bits pour stocker des combinaisons d'options dans un seul entier.
int options = 0;
où OPTION1
peut être défini comme 1, OPTION2
comme 2, OPTION3
comme 4, OPTION4
comme 8, OPTION5
comme 16,. ..
void addOption(int option)
utiliserait l'opérateur |
pour ajouter une option à des options.
boolean hasOption(int option)
utiliserait l'opérateur &
pour tester l'option dans les options.
Je les utilise comme gestionnaire d'options, par exemple dans les listes de contrôle d'accès pour décrire des ressources spécifiques.
Jetez un oeil à cet article http://planetozh.com/blog/2006/05/php-bitwise-operators-example-of-use/
Un lien supplémentaire: http://blog.code-head.com/how-trite-awrite-a-permission-system-using-bits-and-bitwise-operations-in-php
J'ai écrit un petit article de wiki il y a quelque temps montrant un écrivain/lecteur binaire . Cela fonctionne au niveau des bits et montre comment les opérateurs au niveau des bits peuvent être utilisés pour compresser les données. Ce serait probablement un exemple "du monde réel" car il a une application dans les jeux.
Un exemple très spécifique, mais je les ai utilisés pour que mon résolveur de sudoku fonctionne plus vite (j'avais un concours avec un ami)
Chaque colonne, rangée et 3x3 était représentée par un entier non signé et lorsque je définissais des nombres, je marquais le bit approprié pour le nombre défini dans la colonne, la rangée et le carré 3x3 appropriés.
Il était alors très facile de voir quels nombres possibles je pourrais placer dans un carré donné puisque je voudrais OR ensemble la colonne de droite, la ligne et le carré 3x3, puis PAS pour laisser un masque cela représentait les valeurs juridiques possibles pour une position donnée.
J'espère que cela a du sens.
MySQL est une autre application du monde réel qui utilise un type de données appelé SET .
Les opérateurs de bits sont par le SGBD pour stocker le type de données SET. Set peut économiser de l'espace.
Element SET Value Decimal Value
Travel 00000001 1
Sports 00000010 2
Dancing 00000100 4
Fine Dining 00001000 8