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.