Gli operatori bit a bit sono stati inclusi nel linguaggio C per facilitare il lavoro a basso livello con i dati e l'hardware: configurazione di registri, mascheramento, moltiplicazione e divisione per potenze di 2. Le regole per il loro funzionamento si sono consolidate già ai tempi dei processori a 8 e 16 bit.
Spesso ci si sbaglia con gli shift di tipi signed, poiché il risultato dipende dall'implementazione (shift aritmetico o logico), e anche quando si supera il limite della dimensione del tipo. Gli errori possono portare a corruzione dei dati, calcoli errati e comportamento indefinito.
Shift a sinistra (<<): equivalente alla moltiplicazione del valore per 2 elevato alla k (a << k). Riempie sempre con zeri a destra.
Shift a destra (>>): per valori unsigned riempie a sinistra con zero (shift logico), e per signed può riempire con il bit di segno (shift aritmetico) o con zeri (il comportamento dipende dal compilatore).
Esempio:
unsigned int x = 5; // 0000 0101 unsigned int y = x << 1; // 0000 1010 == 10 int z = -4; // 1111 1100 (se 8 bit) int w = z >> 1; // Può rimanere 1111 1110 (-2) o 0111 1110 (dipende dall'implementazione)
Caratteristiche chiave:
Cosa succede quando si sposta un numero negativo a destra con >>?
Il risultato dipende dall'implementazione: la maggior parte delle volte si tratta di uno shift aritmetico che mantiene il segno, ma lo standard non lo garantisce!
Qual è il risultato dello shift di un numero di bit maggiore della larghezza del tipo?
Comportamento indefinito. Ad esempio, 1 << 32 per un tipo a 32 bit può restituire qualsiasi cosa o addirittura far crashare il programma.
È possibile usare operatori bit a bit per numeri in virgola mobile?
No, i tipi standard float e double non supportano operazioni bit a bit. Solo i tipi integer.
Un programmatore spostava un int di 32 per formare una maschera – su alcune piattaforme ciò portava a zero, su altre a un valore non riconoscibile.
Pro:
Contro:
Invece, si utilizzavano valori unsigned e mascheramento della quantità di bit tramite macro, con documentazione chiara e controllo della lunghezza del tipo tramite sizeof.
Pro:
Contro: