Nei titoli e nei testi troverete qualche rimando cinematografico (ebbene si, sono un cinefilo). Se non vi interessano fate finta di non vederli, già che non sono fondamentali per la comprensione dei post...

Di questo blog ho mandato avanti, fino a Settembre 2018, anche una versione in Spagnolo. Potete trovarla su El arte de la programación en C. Buona lettura.

martedì 12 novembre 2013

Bitwise operations!
come usare gli operatori Bitwise in C - pt.1

Anche se questo è un blog di stile (nel caso che qualcuno non se ne fosse ancora accorto...), ho deciso, ancora per un po', di continuare con la mia opera meritoria (che modestia!) di rinfrescare alcuni argomenti che, immagino, tutti hanno letto e/o studiato (magari sul K&R), e poi hanno prontamente dimenticato, perché, diciamocelo, il C contiene delle parti un po' specialistiche e di nicchia, che in alcuni ambienti di programmazione non si usano mai (ma proprio mai!).

Ripetiamo il giochetto dello scorso post: alzi la mano chi ha scritto recentemente codice che usa le operazioni bit a bit. Oppure, alzi la mano, senza prima andare a rileggersi un manuale del C, chi di voi sa usare e/o descrivere perfettamente le operazioni bit a bit. Uhmm... vedo poche mani alzate. Il fatto è che le bitwise operations sono una di quelle parti del C un po' misconosciute, di uso dubbio e infrequente, insomma una di quelle parti di cui, per mancanza di pratica ci si scorda (e ho usato esattamente le stesse parole dello scorso post: sono un ecologista, quando posso riciclo).

Rispetto alle union, oltretutto, devo dire che sulle operazioni bit a bit il fantastico K&R non è particolarmente chiaro e dettagliato, le tratta (come sono) come un argomento di nicchia, e non ti coinvolge con decine di divertenti esempi che ti aiutano a memorizzare definitivamente l'argomento, anzi, per quel che ricordo dell'ultima volta che lo lessi, sono un paio di pagine che scivolano via e che hai già dimenticato quando passi al prossimo capitolo. Beh anche la bibbia K&R (che io considero sacra) ha alcuni punti non proprio coinvolgenti.

Rinfreschiamo: gli operatori di bitwise (che operano sui singoli bit) sono:
"&"  AND
"|"  OR
"^"  XOR
"~"  NOT (complemento a 1)
"<<" SHIFT a sinistra
">>" SHIFT a destra  
     
N.B.:
- il NOT e' un operatore unario: opera su un solo argomento indicato
  sulla destra.
- gli shift sono operatori unari: operano su un solo argomento indicato
  sulla sinistra.
Adesso, senza dilungarci in noiosi sproloqui, passiamo a una piccola tabella e ad alcuni semplici esempi pratici.

Ecco la tabella:
"&":   il risultato è 1 se i due operandi valgono 1. Altrimenti 0.
"|":   il risultato è 0 se i due operandi valgono 0. Altrimenti 1.
"^":   il risultato è 1 se i due operandi sono diversi. Altrimenti 0.
"~":   il risultato è 1 se l'operando vale 0. Se l'operando vale 1 il risultato è 0.
"<<n": il risultato è l'operando con tutti i bit spostati a sinistra di
       n posizioni. 
">>n": il risultato è l'operando con tutti i bit spostati a destra di
       n posizioni.
Ed ecco i semplici esempi pratici:
AND
int a = 74;       // 0 1 0 0 1 0 1 0
int b = 174;      // 1 0 1 0 1 1 1 0
int c = a & b;    // 0 0 0 0 1 0 1 0 risultato c=10

OR
int a = 74;       // 0 1 0 0 1 0 1 0
int b = 174;      // 1 0 1 0 1 1 1 0
int c = a | b;    // 1 1 1 0 1 1 1 0 risultato c=238

XOR
int a = 74;       // 0 1 0 0 1 0 1 0
int b = 174;      // 1 0 1 0 1 1 1 0
int c = a ^ b;    // 1 1 1 0 0 1 0 0 risultato c=228

NOT
int a = 74;       // 0 1 0 0 1 0 1 0
int b = ~a;       // 1 0 1 1 0 1 0 1 risultato b=181

SHIFT a sinistra
int a = 74;       // 0 1 0 0 1 0 1 0
int b = a<<2;     // 0 0 1 0 1 0 0 0 risultato b=296

SHIFT a destra
int a = 74;       // 0 1 0 0 1 0 1 0
int b = a>>2;     // 0 0 0 1 0 0 1 0 risultato b=18
Notare che nelle operazioni di shift i bit nuovi che entrano a destra (nello shift a sinistra) valgono 0, e i bit nuovi che entrano a sinistra (nello shift a destra) valgono 0.

Notare anche che lo shift a destra equivale a una divisione per multipli di 2 (>>1 è una divisione per 2, >>2 è una divisione per 4, ecc.), mentre lo shift a sinistra equivale a una moltiplicazione per multipli di 2 (<<1 è una moltiplicazione per 2, <<2 è una moltiplicazione per 4, ecc.). Queste operazioni di moltiplicazione e divisione sono molto veloci, e si potrebbe essere tentati a usarle per velocizzare il codice: beh, prima di farlo rileggetevi (o leggetevi) questo.

E aggiungo un avvertimento: in base alla dimensione del tipo del operando e alla presenza o meno del bit di segno, le moltiplicazioni e divisioni con shift possono dare risultati inaspettati. Di questo ne parleremo in una prossima puntata, in cui faremo qualche esempio pratico di codice che usa le bitwise operations (e non trattenete il respiro, nel frattempo...).

Ciao e al prossimo post.