Scrivere Software è un piacere. Un programma non solo deve funzionare bene ed essere efficiente (questo si dà per scontato), ma deve essere anche bello ed elegante da leggere, comprensibile e facile da manutenere, sia per l'autore che per eventuali lettori futuri. Programmare bene in C è un'arte.
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.
lunedì 23 dicembre 2013
domenica 1 dicembre 2013
Bitwise operations: Ep.II - L'attacco degli shift
come usare gli operatori Bitwise in C - pt.2
Ok, come promesso qui, torniamo sull'argomento bitwise per descrivere alcuni risultati inaspettati e fornire alcuni semplici esempi pratici.
Cominciamo dalle dolenti note: come anticipato nel post precedente, le moltiplicazioni e divisioni con shift, in base alla dimensione del tipo del operando e alla presenza o meno del bit di segno, possono dare risultati inaspettati. Vediamo un esempio:
Il caso 3, poi, è ancora più subdolo: facendo operazioni con segno (nei casi 1 e 2 ho usato variabili unsigned proprio in preparazione al punto 3) e usando valori negativi, possono succedere cose strane: per la rappresentazione stessa dei numeri negativi in binario (complemento a 2) il bit più a sinistra (MSB) è il bit di segno, e, in questo caso l'operazione di shift è machine-dependent: in base al tipo di CPU possiamo disporre o no dell'estensione di segno (di default, ad esempio, su macchine Intel), per cui lo shift dell'esempio può dare il risultato aspettato (-4/4=-1) o un risultato completamente diverso (-4/4=63 ??). Di nuovo: attenzione!
E adesso è il momento di mostrare alcuni esempi pratici di uso di quanto esposto, che altrimenti, sarebbe know-how fine a se stesso: vediamo come leggere lo stato dei singoli bit di una word usando una maschera:
Facile da leggere e da manutenere: questa l'ho già sentita... ah si: è come dovrebbe essere tutto il S/W che scrive un Analista Programmatore (e peccato che molti analisti programmatori con la minuscola si scordano di questo imperativo quando si siedono davanti a un computer...).
Ciao e al prossimo post!
Cominciamo dalle dolenti note: come anticipato nel post precedente, le moltiplicazioni e divisioni con shift, in base alla dimensione del tipo del operando e alla presenza o meno del bit di segno, possono dare risultati inaspettati. Vediamo un esempio:
Il caso 1 è, evidentemente il caso funzionante: un int è molto più grande degli 8 bit usati per rappresentare il numero di partenza (74), per cui lo shift non perde nessun 1 sulla sinistra (è questo il possibile problema) e il risultato è corretto (74x4=296). Se usiamo però (caso 2) un char (8 bit) durante lo shift perdiamo un 1 e il risultato va in overflow (74x4=40 ??). Quindi attenzione!void main() { // 1) SHIFT a sinistra con unsigned int unsigned int a, b; a = 74; // 0 0 1 0 0 1 0 1 0 b = a << 2; // 1 0 0 1 0 1 0 0 0 risultato b=296 printf("var = %d; var << 2 = %d\n", a, b); // 2) SHIFT a sinistra con unsigned char unsigned char c, d; c = 74; // 0 1 0 0 1 0 1 0 d = c << 2; // 0 0 1 0 1 0 0 0 risultato d=40 printf("var = %d; var << 2 = %d\n", c, d); // 3) SHIFT a destra con signed char (o int) char e, f; e = -4; // 1 1 1 1 1 1 0 0 f = e >> 2; // 1 1 1 1 1 1 1 1 risultato f=-1 printf("var = %d: var >> 2 = %d\n", e, f); // N.B.: senza estensione di segno sarebbe: // e = -4; // 1 1 1 1 1 1 0 0 // f = e >> 2; // 0 0 1 1 1 1 1 1 risultato f=63 }
Il caso 3, poi, è ancora più subdolo: facendo operazioni con segno (nei casi 1 e 2 ho usato variabili unsigned proprio in preparazione al punto 3) e usando valori negativi, possono succedere cose strane: per la rappresentazione stessa dei numeri negativi in binario (complemento a 2) il bit più a sinistra (MSB) è il bit di segno, e, in questo caso l'operazione di shift è machine-dependent: in base al tipo di CPU possiamo disporre o no dell'estensione di segno (di default, ad esempio, su macchine Intel), per cui lo shift dell'esempio può dare il risultato aspettato (-4/4=-1) o un risultato completamente diverso (-4/4=63 ??). Di nuovo: attenzione!
E adesso è il momento di mostrare alcuni esempi pratici di uso di quanto esposto, che altrimenti, sarebbe know-how fine a se stesso: vediamo come leggere lo stato dei singoli bit di una word usando una maschera:
semplice no? E la stessa operazione si può fare con una macro:void main() { // uso di una maschera per leggere i bit di una word unsigned char mask = 1; // 0 0 0 0 0 0 0 1 unsigned char word = 74; // 0 1 0 0 1 0 1 0 // loop di lettura int i; for (i = 0; i < 8; i++) printf("il bit %d della word è %s\n", i, (word & mask<<i) ? "ON" : "OFF"); }
E poi, visto che questo è un blog di stile, vediamo un modo con una una buona estetica per leggere degli input di un dispositivo, per esempio i fine corsa di un sistema elettromeccanico che dobbiamo controllare col nostro amato C:#define INPUT(w, i) (w & 0x01<<i) void main() { // uso di una macro per leggere i bit di una word unsigned char i_word = 74; // 0 1 0 0 1 0 1 0 // loop di lettura int i; for (i = 0; i < 8; i++) printf("il bit %d della word è %s\n", i, INPUT(i_word, i) ? "ON" : "OFF"); }
Ecco, l'esempio appena mostrato indica una maniera, semplice ed elegante, per descrivere degli input (usando dei mnemonici auto-esplicativi) che può risultare utile per scrivere del Software di controllo di dispositivi Hardware, facile da leggere e da manutenere.#define INPUT_FC1 (in_word & 0x01<<0) #define INPUT_FC2 (in_word & 0x01<<1) void main() { // uso di una define per ogni bit da leggere di una word unsigned char in_word = 74; // 0 1 0 0 1 0 1 0 // lettura printf("il bit FC1 della word è %s\n", INPUT_FC1 ? "ON" : "OFF"); printf("il bit FC2 della word è %s\n", INPUT_FC2 ? "ON" : "OFF"); }
Facile da leggere e da manutenere: questa l'ho già sentita... ah si: è come dovrebbe essere tutto il S/W che scrive un Analista Programmatore (e peccato che molti analisti programmatori con la minuscola si scordano di questo imperativo quando si siedono davanti a un computer...).
Ciao e al prossimo post!
Iscriviti a:
Post (Atom)