L'operazione di rotazione circolare (rotary/circular shift) è uno spostamento dei bit di un numero di un certo numero di posizioni con il riutilizzo dei bit "persi" all'estremità opposta. Nel linguaggio C non esiste un operatore incorporato per questo compito; tale soluzione è storicamente legata alla portabilità della libreria standard e alla necessità di definire esplicitamente il comportamento per diverse piattaforme.
Il problema è che gli operatori di shift standard (<<, >>) non effettuano uno shift circolare: spostano solo i bit e i "persi" vengono sostituiti da zeri. Per lo shift circolare è necessario combinare esplicitamente i risultati di due shift e mascherare il risultato con il numero di bit specificato.
La soluzione è implementare lo shift circolare manualmente. Per un numero unsigned a 32 bit, appare così:
uint32_t rotate_left(uint32_t value, unsigned int shift) { return (value << shift) | (value >> (32 - shift)); } uint32_t rotate_right(uint32_t value, unsigned int shift) { return (value >> shift) | (value << (32 - shift)); }
Caratteristiche chiave:
L'operatore << o >> può implementare uno shift circolare senza operazioni aggiuntive?
No. I normali shift sostituiscono i bit che escono dai limiti con zeri, non li traslano dall'altra parte.
Cosa succede se si effettua uno shift della dimensione del tipo (shift uguale al numero di bit del numero)?
Il comportamento non è definito (Undefined Behavior secondo lo standard C), è necessario effettuare sempre lo shift modulo la dimensione del tipo.
È sicuro effettuare un rotary shift con questi operatori per i tipi signed?
No, utilizza sempre tipi unsigned, poiché gli shift bit a bit per i tipi signed si comportano diversamente a seconda del compilatore e dell'architettura.
Utilizzare uno shift normale per uno spostamento circolare:
uint32_t x = 0xFA3C0F00; uint32_t y = x << 5; // Non ha carattere circolare
Vantaggi:
Svantaggi:
Utilizzare una funzione manuale di rotary shift tenendo conto della dimensione del tipo e proteggendosi dall'UB:
uint32_t x = 0xFA3C0F00; uint32_t y = rotate_left(x, 5);
Vantaggi:
Svantaggi: