Riporto qui un semplice metodo per recuperare il valore incorporato in un byte, nel caso in cui si abbiano più informazioni entro un unico byte:
C#:
private static int GetBits(byte b, int offset, int length)
{
// shifta di un numero di volte pari a offset
b >>= offset;
// esegui mascheratura
b &= (byte)((1 << length) - 1);
return b;
}
Se vi è chiaro ciò che fa questa funzione, e in particolare l’operazione di mascheratura, saltate pure il resto, altrimenti forse è il caso di fare un piccolo ripasso delle operazioni bitwise.
Prima di affrontare il caso generale vediamo due semplici metodi di estrazione, applicati ad un esempio concreto.
La specifica MIDI del Meta Evento “SMPTE Offset” prevede una sequenza di byte così fatta:
dove il byte che contiene l’ora contiene anche il valore di frame rate:
e impone che il bit più significativo (quello più a sinistra, per intenderci) sia sempre pari a zero.
Operazione di Mascheratura:
Volendo recuperare il valore di “hour”, dobbiamo mascherare (cioè rendere nulli) gli altri bit. Useremo quindi una maschera con i tre bit più significativi (ovvero “più a sinistra”) pari a zero e i restanti pari a 1:
dove 31 è il valore decimale di “00011111” e “&” è l’operatore logico AND, eseguito bit su bit.
Operazione di Shift:
Volendo recuperare il valore di frame rate, in questo caso specifico, basta spostare i bit verso destra di cinque posizioni:
C#:
frameRate = theByte >> 5;
Il caso generale:
In generale, volendo recuperare il valore relativo ad una porzione di byte, dobbiamo combinare le due precedenti tecniche, prima shiftando e poi mascherando, come riportato nella funzione di cui sopra.
Per illustrare la parte interessante, ovvero la creazione della maschera, utilizziamo un esempio concreto:
dopo l’operazione di shifting si ha:
Appare evidente che mascheratura va effettuata con una maschera pari a:
Ma in generale, come possiamo costruire la maschera a partire dai paramentri “offset” e “length” ?
La risposta è semplice se consideriamo l’equivalenza:
Dunque per creare la maschera ci basta prendere “00000001”, shiftarlo verso sinista di un numero di volte pari a “length” e sottrargli “00000001”.
C#:
// Crea maschera - step 1
byte mask = 1;
// Crea maschera - step 2 (shifta di un numero di volte pari a length)
mask <<= length;
// Crea maschera - step 3 (sottrai 1)
mask -= 1;
Da notare che nella routine, poiché la maschera viene creata “al volo” in un’unica riga, occorre esplicitare che le operazioni di shift e di sottrazione sono da effettuare sul tipo byte (e non su int32, come farebbe il compilatore). Ed è per questo motivo che viene usato il casting esplicito a (byte) senza il quale il compilatore si rifiuta di compilare visto che un casting implicito da int32 a byte provocherebbe un’evidente possibilità di perdita di dati.
That’s all folks!