C++
Opérateurs de bits
Recherche…
Remarques
Les opérations de décalage de bits ne sont pas portables pour toutes les architectures de processeur, différents processeurs peuvent avoir des largeurs de bits différentes. En d'autres termes, si vous écriviez
int a = ~0;
int b = a << 1;
Cette valeur serait différente sur une machine 64 bits par rapport à une machine 32 bits, ou entre un processeur x86 et un processeur PIC.
Endian-ness n'a pas besoin d'être pris en compte pour les opérations sur les bits elles-mêmes, c'est-à-dire que le décalage vers la droite ( >>
) décale les bits vers le bit le moins significatif et qu'un XOR exécute un bit exclusif ou sur les bits. Endian-ness n'a besoin d'être pris en compte que par les données elles-mêmes, c'est-à-dire que si l'endian-ness est une préoccupation pour votre application, il s'agit d'une préoccupation indépendamment des opérations sur les bits.
& - bitwise AND
int a = 6; // 0110b (0x06)
int b = 10; // 1010b (0x0A)
int c = a & b; // 0010b (0x02)
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
Sortie
a = 6, b = 10, c = 2
Pourquoi
Un peu sage AND
fonctionne sur le niveau du bit et utilise la table de vérité booléenne suivante:
TRUE AND TRUE = TRUE
TRUE AND FALSE = FALSE
FALSE AND FALSE = FALSE
Lorsque la valeur binaire pour a
( 0110
) et la valeur binaire pour b
( 1010
) sont AND
ensemble, nous obtenons la valeur binaire de 0010
:
int a = 0 1 1 0
int b = 1 0 1 0 &
---------
int c = 0 0 1 0
Le bit sages ET ne modifie pas la valeur des valeurs d'origine, à moins que cela ne soit spécifiquement attribué à l'utilisation de l'opérateur de mappage par bits &=
:
int a = 5; // 0101b (0x05)
a &= 10; // a = 0101b & 1010b
| - bit à bit OU
int a = 5; // 0101b (0x05)
int b = 12; // 1100b (0x0C)
int c = a | b; // 1101b (0x0D)
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
Sortie
a = 5, b = 12, c = 13
Pourquoi
Un peu sage OR
fonctionne sur le niveau du bit et utilise la table de vérité booléenne suivante:
true OR true = true
true OR false = true
false OR false = false
Lorsque la valeur binaire pour a
( 0101
) et la valeur binaire pour b
( 1100
) sont OR
ensemble, nous obtenons la valeur binaire de 1101
:
int a = 0 1 0 1
int b = 1 1 0 0 |
---------
int c = 1 1 0 1
Le bit sages OU ne modifie pas la valeur des valeurs d'origine à moins que ce soit spécifiquement affecté à l'aide de l'opérateur composé d'affectation par bit |=
:
int a = 5; // 0101b (0x05)
a |= 12; // a = 0101b | 1101b
^ - bit à bit XOR (OU exclusif)
int a = 5; // 0101b (0x05)
int b = 9; // 1001b (0x09)
int c = a ^ b; // 1100b (0x0C)
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
Sortie
a = 5, b = 9, c = 12
Pourquoi
Un peu XOR
(exclusif ou) opère au niveau du bit et utilise la table de vérité booléenne suivante:
true OR true = false
true OR false = true
false OR false = false
Notez qu'avec une opération XOR true OR true = false
où avec des opérations true AND/OR true = true
, d'où la nature exclusive de l'opération XOR.
En utilisant ceci, lorsque la valeur binaire pour a
( 0101
) et la valeur binaire pour b
( 1001
) sont XOR
ensemble, nous obtenons la valeur binaire de 1100
:
int a = 0 1 0 1
int b = 1 0 0 1 ^
---------
int c = 1 1 0 0
Le bit XOR ne modifie pas la valeur des valeurs d'origine, à moins que cela ne soit spécifiquement attribué à l'utilisation de l'opérateur composé d'affectation par bit ^=
:
int a = 5; // 0101b (0x05)
a ^= 9; // a = 0101b ^ 1001b
Le bit XOR peut être utilisé de nombreuses manières et est souvent utilisé dans les opérations de masque binaire pour le chiffrement et la compression.
Remarque: L’exemple suivant est souvent présenté comme un exemple d’astuce. Mais ne devrait pas être utilisé dans le code de production (il existe de meilleures méthodes std::swap()
pour obtenir le même résultat).
Vous pouvez également utiliser une opération XOR pour échanger deux variables sans temporaire:
int a = 42;
int b = 64;
// XOR swap
a ^= b;
b ^= a;
a ^= b;
std::cout << "a = " << a << ", b = " << b << "\n";
Pour produire cela, vous devez ajouter une vérification pour vous assurer qu'il peut être utilisé.
void doXORSwap(int& a, int& b)
{
// Need to add a check to make sure you are not swapping the same
// variable with itself. Otherwise it will zero the value.
if (&a != &b)
{
// XOR swap
a ^= b;
b ^= a;
a ^= b;
}
}
Donc, bien que cela ressemble à une astuce en vase clos, ce n'est pas utile en code réel. xor n'est pas une opération logique de base, mais une combinaison d'autres opérations: a ^ c = ~ (a & c) & (a | c)
également en 2015+ les variables de compilateurs peuvent être assignées comme binaires:
int cn=0b0111;
~ - bitwise NOT (complément unaire)
unsigned char a = 234; // 1110 1010b (0xEA)
unsigned char b = ~a; // 0001 0101b (0x15)
std::cout << "a = " << static_cast<int>(a) <<
", b = " << static_cast<int>(b) << std::endl;
Sortie
a = 234, b = 21
Pourquoi
Un peu sage NOT
(complément unaire) fonctionne sur le niveau du bit et chaque bit est réfléchi. Si c'est un 1
, il est changé en 0
, si c'est un 0
, il est changé en 1
. Le bit not not NOT a le même effet que XOR sur une valeur par rapport à la valeur max pour un type spécifique:
unsigned char a = 234; // 1110 1010b (0xEA)
unsigned char b = ~a; // 0001 0101b (0x15)
unsigned char c = a ^ ~0;
Le bit not NON peut aussi être un moyen pratique de vérifier la valeur maximale d'un type entier spécifique:
unsigned int i = ~0;
unsigned char c = ~0;
std::cout << "max uint = " << i << std::endl <<
"max uchar = " << static_cast<short>(c) << std::endl;
Le bit not not NOT ne change pas la valeur de la valeur d'origine et n'a pas d'opérateur d'affectation composé, vous ne pouvez donc pas faire a ~= 10
par exemple.
Le bit not not NOT ( ~
) ne doit pas être confondu avec le NOT logique ( !
); où un peu sage ne retournera pas chaque bit, un NOT logique utilisera la valeur entière pour effectuer son opération, en d'autres termes (!1) != (~1)
<< - décalage gauche
int a = 1; // 0001b
int b = a << 1; // 0010b
std::cout << "a = " << a << ", b = " << b << std::endl;
Sortie
a = 1, b = 2
Pourquoi
Le décalage gauche sage décalera les bits de la valeur de gauche ( a
) le nombre spécifié à droite ( 1
), remplissant essentiellement les bits les moins significatifs avec les 0, déplaçant ainsi la valeur de 5
( 0000 0101
binaire) à gauche 4 fois (par exemple 5 << 4
) donneront la valeur de 80
(binaire 0101 0000
). Vous remarquerez peut-être que le fait de déplacer une valeur vers la gauche 1 fois est également identique à la multiplication de la valeur 2, par exemple:
int a = 7;
while (a < 200) {
std::cout << "a = " << a << std::endl;
a <<= 1;
}
a = 7;
while (a < 200) {
std::cout << "a = " << a << std::endl;
a *= 2;
}
Mais il convient de noter que l’opération de décalage vers la gauche décale tous les bits vers la gauche, y compris le bit de signe, par exemple:
int a = 2147483647; // 0111 1111 1111 1111 1111 1111 1111 1111
int b = a << 1; // 1111 1111 1111 1111 1111 1111 1111 1110
std::cout << "a = " << a << ", b = " << b << std::endl;
Sortie possible: a = 2147483647, b = -2
Bien que certains compilateurs donneront des résultats qui semblent attendus, il convient de noter que si vous laissez un décalage sur un numéro signé pour que le bit de signe soit affecté, le résultat est indéfini . Il est également indéfini si le nombre de bits que vous souhaitez décaler est un nombre négatif ou est supérieur au nombre de bits que le type à gauche peut contenir, exemple:
int a = 1;
int b = a << -1; // undefined behavior
char c = a << 20; // undefined behavior
Le décalage gauche au niveau du bit ne modifie pas la valeur des valeurs d’origine, sauf si l’opérateur spécifique d’attribution de bits <<=
:
int a = 5; // 0101b
a <<= 1; // a = a << 1;
>> - décalage vers la droite
int a = 2; // 0010b
int b = a >> 1; // 0001b
std::cout << "a = " << a << ", b = " << b << std::endl;
Sortie
a = 2, b = 1
Pourquoi
Le décalage vers la droite permet de décaler les bits de la valeur de gauche ( a
) du nombre spécifié à droite ( 1
); il convient de noter que si l'opération d'un décalage à droite est standard, ce qui arrive aux bits d'un décalage à droite sur un nombre négatif signé est défini par l'implémentation et ne peut donc pas être garanti portable, par exemple:
int a = -2;
int b = a >> 1; // the value of b will be depend on the compiler
Il est également indéfini si le nombre de bits que vous souhaitez décaler est un nombre négatif, par exemple:
int a = 1;
int b = a >> -1; // undefined behavior
Le décalage vers la droite au niveau du bit ne modifie pas la valeur des valeurs d’origine, sauf si elles sont spécifiquement associées à l’utilisation de l’opérateur composé d’affectation par bit >>=
:
int a = 2; // 0010b
a >>= 1; // a = a >> 1;