Fai un and sui soli bit non-di segno, quindi se il bit di segno è attivo aggiungi al risultato -2^(posizione bit segno).
Supponendo che il tuo numero "raw" stia in uno short senza segno:
codice:
short rawtoshort(unsigned short raw, unsigned int bits)
{
unsigned short signmask=1<<(bits-1);
return ((raw&signmask)?(-(short)signmask):0) + (raw&(signmask-1));
}
Questo funziona indipendentemente da come siano rappresentati gli interi sulla tua piattaforma. Se invece assumi che sia l'input che l'output siano in complemento a due, allora si può fare:
codice:
short rawtoshort(unsigned short raw, unsigned int bits)
{
unsigned short signmask=1<<(bits-1);
raw|=(raw&signmask)?(~(signmask-1)):0;
short ret;
// necessario dato che in C il type-punning via cast di puntatori non è standard, e così pure un buon
// numero di operazioni bit-a-bit sui tipi con segno
memcpy(&ret, &raw, sizeof(ret));
return ret;
}
in ogni caso, è più la fatica del guadagno usare questo secondo metodo in C, mentre con ogni probabilità è un pelo più efficiente/compatto rispetto all'altro se scritto direttamente in assembly.