C++
Operatori di bit
Ricerca…
Osservazioni
Le operazioni di spostamento dei bit non sono trasferibili su tutte le architetture dei processori, i processori diversi possono avere diverse larghezze di bit. In altre parole, se hai scritto
int a = ~0;
int b = a << 1;
Questo valore sarebbe diverso su una macchina a 64 bit rispetto a una macchina a 32 bit o su un processore basato su x86 su un processore basato su PIC.
L'endianità non ha bisogno di essere presa in considerazione per le operazioni bit-wise stesse, cioè lo spostamento a destra ( >>
) sposterà i bit verso il bit meno significativo e uno XOR eseguirà un esclusivo o sui bit. L'endianità deve essere presa in considerazione solo con i dati stessi, ovvero se l'endianità è una preoccupazione per l'applicazione, è una preoccupazione indipendentemente dalle operazioni bit-saggio.
& - AND bit a bit
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;
Produzione
a = 6, b = 10, c = 2
Perché
Un po 'saggio AND
opera a livello di bit e utilizza la seguente tabella di verità booleana:
TRUE AND TRUE = TRUE
TRUE AND FALSE = FALSE
FALSE AND FALSE = FALSE
Quando il valore binario per a
( 0110
) e il valore binario per b
( 1010
) sono AND
'ed insieme otteniamo il valore binario di 0010
:
int a = 0 1 1 0
int b = 1 0 1 0 &
---------
int c = 0 0 1 0
Il bit Wise AND non modifica il valore dei valori originali se non è specificamente assegnato all'utilizzo dell'operatore composto di assegnazione bit saggio &=
:
int a = 5; // 0101b (0x05)
a &= 10; // a = 0101b & 1010b
| - OR bit a bit
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;
Produzione
a = 5, b = 12, c = 13
Perché
Un po 'saggio OR
opera a livello di bit e usa la seguente tabella di verità booleana:
true OR true = true
true OR false = true
false OR false = false
Quando il valore binario di a
( 0101
) e il valore binario di b
( 1100
) sono OR
"ed insieme otteniamo il valore binario di 1101
:
int a = 0 1 0 1
int b = 1 1 0 0 |
---------
int c = 1 1 0 1
L'OR bit-saggio non modifica il valore dei valori originali se non è specificamente assegnato all'utilizzo dell'operatore composto assegnazione bit saggio |=
:
int a = 5; // 0101b (0x05)
a |= 12; // a = 0101b | 1101b
^ - XOR bit a bit (OR esclusivo)
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;
Produzione
a = 5, b = 9, c = 12
Perché
Un po 'saggio XOR
(esclusivo o) opera a livello di bit e utilizza la seguente tabella di verità booleana:
true OR true = false
true OR false = true
false OR false = false
Si noti che con un'operazione XOR true OR true = false
dove, come con le operazioni true AND/OR true = true
, quindi la natura esclusiva dell'operazione XOR.
Usando questo, quando il valore binario di a
( 0101
) e il valore binario di b
( 1001
) sono XOR
'ed insieme otteniamo il valore binario di 1100
:
int a = 0 1 0 1
int b = 1 0 0 1 ^
---------
int c = 1 1 0 0
Il bit XOR bit non modifica il valore dei valori originali se non è specificamente assegnato all'utilizzo dell'operatore composto assegnazione bit saggio ^=
:
int a = 5; // 0101b (0x05)
a ^= 9; // a = 0101b ^ 1001b
Il bit XOR può essere utilizzato in molti modi ed è spesso utilizzato nelle operazioni di bit mask per la crittografia e la compressione.
Nota: il seguente esempio viene spesso mostrato come esempio di un bel trucco. Ma non dovrebbe essere usato nel codice di produzione (ci sono modi migliori per std::swap()
per ottenere lo stesso risultato).
Puoi anche utilizzare un'operazione XOR per scambiare due variabili senza un temporaneo:
int a = 42;
int b = 64;
// XOR swap
a ^= b;
b ^= a;
a ^= b;
std::cout << "a = " << a << ", b = " << b << "\n";
Per la produzione di questo è necessario aggiungere un assegno per assicurarsi che possa essere utilizzato.
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;
}
}
Quindi anche se sembra un bel trucco in isolamento non è utile nel codice reale. xor non è un'operazione logica di base, ma una combinazione di altre: a ^ c = ~ (a & c) & (a | c)
anche nel 2015 le variabili dei compilatori possono essere assegnate come binarie:
int cn=0b0111;
~ - bit per bit NOT (complemento unario)
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;
Produzione
a = 234, b = 21
Perché
Un po 'saggio NOT
(complemento unario) opera a livello di bit e semplicemente capovolge ogni bit. Se è un 1
, è cambiato in uno 0
, se è uno 0
, è cambiato in un 1
. Il bit saggio NON ha lo stesso effetto di XOR un valore rispetto al valore massimo per un tipo specifico:
unsigned char a = 234; // 1110 1010b (0xEA)
unsigned char b = ~a; // 0001 0101b (0x15)
unsigned char c = a ^ ~0;
Il bit bit NOT può anche essere un modo conveniente per verificare il valore massimo per un tipo specifico integrale:
unsigned int i = ~0;
unsigned char c = ~0;
std::cout << "max uint = " << i << std::endl <<
"max uchar = " << static_cast<short>(c) << std::endl;
Il bit-saggio NOT non cambia il valore del valore originale e non ha un operatore di assegnazione composto, quindi non puoi fare a ~= 10
per esempio.
Il bit saggio NON ( ~
) non deve essere confuso con il logico NOT ( !
); dove un po 'saggio NON capovolgerà ogni bit, un NOT logico userà l'intero valore per eseguire la sua operazione, in altre parole (!1) != (~1)
<< - spostamento a sinistra
int a = 1; // 0001b
int b = a << 1; // 0010b
std::cout << "a = " << a << ", b = " << b << std::endl;
Produzione
a = 1, b = 2
Perché
Il bit shift sinistro sposterà i bit del valore della mano sinistra ( a
) il numero specificato a destra ( 1
), in pratica riempendo i bit meno significativi con 0, quindi spostando il valore di 5
(binario 0000 0101
) a sinistra 4 volte (es. 5 << 4
) produrrà il valore di 80
(binario 0101 0000
). È possibile notare che lo spostamento di un valore a sinistra 1 volta è uguale a moltiplicare il valore per 2, ad esempio:
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;
}
Ma va notato che l'operazione di spostamento a sinistra sposta tutti i bit a sinistra, incluso il bit di segno, ad esempio:
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;
Uscita possibile: a = 2147483647, b = -2
Mentre alcuni compilatori produrranno risultati che sembrano prevedibili, è opportuno notare che se si lascia un numero con segno maiuscolo in modo che il bit del segno sia interessato, il risultato non è definito . È anche indefinito se il numero di bit che desideri spostare è un numero negativo o è maggiore del numero di bit che il tipo a sinistra può contenere, ad esempio:
int a = 1;
int b = a << -1; // undefined behavior
char c = a << 20; // undefined behavior
Il cambio bit left shift non cambia il valore dei valori originali a meno che non sia specificamente assegnato all'utilizzo dell'operatore composto assegnazione bit saggio <<=
:
int a = 5; // 0101b
a <<= 1; // a = a << 1;
>> - spostamento a destra
int a = 2; // 0010b
int b = a >> 1; // 0001b
std::cout << "a = " << a << ", b = " << b << std::endl;
Produzione
a = 2, b = 1
Perché
Lo spostamento bit destro corretto sposterà i bit del valore della mano sinistra ( a
) il numero specificato a destra ( 1
); va notato che mentre l'operazione di un passaggio a destra è standard, ciò che accade ai bit di uno spostamento a destra su un numero negativo con segno è definito dall'implementazione e quindi non può essere garantito che sia portatile, ad esempio:
int a = -2;
int b = a >> 1; // the value of b will be depend on the compiler
È anche indefinito se il numero di bit che desideri spostare è un numero negativo, ad esempio:
int a = 1;
int b = a >> -1; // undefined behavior
Il bit right shift non cambia il valore dei valori originali a meno che non sia specificatamente assegnato all'operatore di assegnazione bit saggio bit >>=
:
int a = 2; // 0010b
a >>= 1; // a = a >> 1;