C++
Bit-operators
Zoeken…
Opmerkingen
Bit shift-bewerkingen zijn niet overdraagbaar in alle processorarchitecturen, verschillende processors kunnen verschillende bitbreedtes hebben. Met andere woorden, als je schreef
int a = ~0;
int b = a << 1;
Deze waarde zou anders zijn op een 64-bit machine versus op een 32-bit machine, of van een x86-gebaseerde processor naar een PIC-gebaseerde processor.
Endian-heid hoeft niet in aanmerking te worden genomen voor de bitsgewijze bewerkingen zelf, dat wil zeggen dat de juiste verschuiving ( >>
) de bits naar de minst significante bit verschuift en een XOR een exclusieve of op de bits uitvoert. Endian-heid hoeft alleen in aanmerking te worden genomen met de gegevens zelf, dat wil zeggen, als endian-heid een zorg is voor uw toepassing, is het een zorg, ongeacht bit-wijs operaties.
& - beetje bij beetje EN
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;
uitgang
a = 6, b = 10, c = 2
Waarom
Een beetje wijs AND
werkt op bitniveau en gebruikt de volgende Booleaanse waarheidstabel:
TRUE AND TRUE = TRUE
TRUE AND FALSE = FALSE
FALSE AND FALSE = FALSE
Wanneer de binaire waarde voor a
( 0110
) en de binaire waarde voor b
( 1010
) samen zijn AND
'n krijgen we de binaire waarde van 0010
:
int a = 0 1 1 0
int b = 1 0 1 0 &
---------
int c = 0 0 1 0
De bitsgewijze AND verandert de waarde van de oorspronkelijke waarden niet, tenzij specifiek toegewezen aan het gebruik van de bitsgewijze toewijzing samengestelde operator &=
:
int a = 5; // 0101b (0x05)
a &= 10; // a = 0101b & 1010b
| - beetje bij beetje OF
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;
uitgang
a = 5, b = 12, c = 13
Waarom
Een beetje verstandig OR
werkt op bitniveau en gebruikt de volgende Booleaanse waarheidstabel:
true OR true = true
true OR false = true
false OR false = false
Wanneer de binaire waarde voor a
( 0101
) en de binaire waarde voor b
( 1100
) samen zijn OR
's krijgen we de binaire waarde van 1101
:
int a = 0 1 0 1
int b = 1 1 0 0 |
---------
int c = 1 1 0 1
De bitgewijze OF wijzigt de waarde van de oorspronkelijke waarden niet, tenzij specifiek toegewezen aan het gebruik van de bitgewijze toewijzing samengestelde operator |=
:
int a = 5; // 0101b (0x05)
a |= 12; // a = 0101b | 1101b
^ - bitgewijs XOR (exclusief OF)
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;
uitgang
a = 5, b = 9, c = 12
Waarom
Een beetje wijs XOR
(exclusief of) werkt op bitniveau en gebruikt de volgende Booleaanse waarheidstabel:
true OR true = false
true OR false = true
false OR false = false
Merk op dat bij een XOR-bewerking true OR true = false
als bij operaties true AND/OR true = true
, vandaar het exclusieve karakter van de XOR-bewerking.
Als we hiermee de binaire waarde voor a
( 0101
) en de binaire waarde voor b
( 1001
) samen XOR
, krijgen we de binaire waarde van 1100
:
int a = 0 1 0 1
int b = 1 0 0 1 ^
---------
int c = 1 1 0 0
De bitgewijze XOR wijzigt de waarde van de oorspronkelijke waarden niet, tenzij specifiek toegewezen aan het gebruik van de bitgewijze toewijzingscombinatie ^=
:
int a = 5; // 0101b (0x05)
a ^= 9; // a = 0101b ^ 1001b
De bitgewijze XOR kan op vele manieren worden gebruikt en wordt vaak gebruikt in bitmaskerbewerkingen voor codering en compressie.
Opmerking: het volgende voorbeeld wordt vaak getoond als een voorbeeld van een leuke truc. Maar mag niet worden gebruikt in productiecode (er zijn betere manieren om std::swap()
te gebruiken om hetzelfde resultaat te bereiken).
U kunt ook een XOR-bewerking gebruiken om twee variabelen zonder een tijdelijke te verwisselen:
int a = 42;
int b = 64;
// XOR swap
a ^= b;
b ^= a;
a ^= b;
std::cout << "a = " << a << ", b = " << b << "\n";
Om dit productionaliseren, moet u een vinkje toevoegen om te controleren of het kan worden gebruikt.
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;
}
}
Dus hoewel het op zichzelf een leuke truc lijkt, is het niet nuttig in echte code. xor is geen logische basisbewerking, maar een combinatie van anderen: a ^ c = ~ (a & c) & (a | c)
ook in 2015+ compilers kunnen variabelen worden toegewezen als binair:
int cn=0b0111;
~ - bitwise NOT (unaire aanvulling)
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;
uitgang
a = 234, b = 21
Waarom
Een beetje verstandig NOT
(unaire aanvulling) werkt op bitniveau en draait gewoon elke bit om. Als het een 1
, is het gewijzigd in een 0
, als het een 0
, is het gewijzigd in een 1
. Qua bit heeft NOT hetzelfde effect als het XOR'en van een waarde tegen de maximale waarde voor een specifiek type:
unsigned char a = 234; // 1110 1010b (0xEA)
unsigned char b = ~a; // 0001 0101b (0x15)
unsigned char c = a ^ ~0;
Qua bits kan NOT ook een handige manier zijn om de maximale waarde voor een specifiek integraaltype te controleren:
unsigned int i = ~0;
unsigned char c = ~0;
std::cout << "max uint = " << i << std::endl <<
"max uchar = " << static_cast<short>(c) << std::endl;
Qua bit wijzigt NOT de waarde van de oorspronkelijke waarde niet en heeft geen samengestelde toewijzingsoperator, dus u kunt bijvoorbeeld geen a ~= 10
.
Het beetje verstandig NIET ( ~
) moet niet worden verward met het logische NIET ( !
); waar een beetje wijs NIET elke bit omdraait, gebruikt een logische NIET de hele waarde om zijn bewerking uit te voeren, met andere woorden (!1) != (~1)
<< - shift links
int a = 1; // 0001b
int b = a << 1; // 0010b
std::cout << "a = " << a << ", b = " << b << std::endl;
uitgang
a = 1, b = 2
Waarom
De linker bitgewijze verschuiving verplaatst de bits van de linkerhandwaarde ( a
) het nummer dat rechts is opgegeven ( 1
), waarbij in wezen de minst significante bits met nullen worden opgevuld, dus de waarde van 5
(binair 0000 0101
) naar links schuiven 4 keer (bijvoorbeeld 5 << 4
) levert de waarde 80
(binair 0101 0000
). Je merkt misschien op dat het 1 keer naar links schuiven hetzelfde is als het vermenigvuldigen van de waarde met 2, bijvoorbeeld:
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;
}
Maar er moet worden opgemerkt dat de linker shift-operatie alle bits naar links zal verplaatsen, inclusief het tekenbit, bijvoorbeeld:
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;
Mogelijke output: a = 2147483647, b = -2
Hoewel sommige compilers resultaten opleveren die verwacht worden, moet worden opgemerkt dat als u een getekend nummer verlaat zodat het tekenbit wordt beïnvloed, het resultaat niet is gedefinieerd . Het is ook ongedefinieerd als het aantal bits dat u wilt verplaatsen een negatief getal is of groter is dan het aantal bits dat het type links kan bevatten, bijvoorbeeld:
int a = 1;
int b = a << -1; // undefined behavior
char c = a << 20; // undefined behavior
De bitgewijze linkerverschuiving verandert de waarde van de oorspronkelijke waarden niet, tenzij specifiek toegewezen aan het gebruik van de bitgewijze toewijzing samengestelde operator <<=
:
int a = 5; // 0101b
a <<= 1; // a = a << 1;
>> - juiste shift
int a = 2; // 0010b
int b = a >> 1; // 0001b
std::cout << "a = " << a << ", b = " << b << std::endl;
uitgang
a = 2, b = 1
Waarom
De juiste bitgewijze verschuiving verschuift de bits van de linkerhandwaarde ( a
) het nummer dat rechts is opgegeven ( 1
); Opgemerkt moet worden dat, hoewel de werking van een rechtse shift standaard is, wat er gebeurt met de bits van een rechtse shift op een ondertekend negatief nummer, de implementatie is gedefinieerd en dus niet kan worden gegarandeerd dat het draagbaar is, bijvoorbeeld:
int a = -2;
int b = a >> 1; // the value of b will be depend on the compiler
Het is ook ongedefinieerd als het aantal bits waarnaar u wilt verschuiven een negatief getal is, bijvoorbeeld:
int a = 1;
int b = a >> -1; // undefined behavior
De bitgewijze juiste verschuiving verandert de waarde van de oorspronkelijke waarden niet, tenzij specifiek toegewezen aan het gebruik van de bitgewijze toewijzing samengestelde operator >>=
:
int a = 2; // 0010b
a >>= 1; // a = a >> 1;