2011-01-24 14 views
6

Ho un array di caratteri non firmato con 2 elementi che rappresenta un numero intero con segno. Come posso convertire questi 2 byte in un numero intero con segno?Conversione di caratteri non firmati in numero intero con segno

Edit: L'array char unsigned è little endian

+0

devi guardare fuori per ordine dei byte , vedi http://en.wikipedia.org/wiki/Endianness –

+0

Ci sono diversi modi in cui due 'char unsigned 'potrebbero rappresentare un intero con segno. Dovresti essere più specifico su questo. –

risposta

6

Per la massima sicurezza, utilizzare

int i = *(signed char *)(&c[0]); 
i *= 1 << CHAR_BIT; 
i |= c[1]; 

per big endian. Swap c[0] e c[1] per little endian.

(Spiegazione: interpretiamo il byte alla c[0] come signed char, poi spostamento a sinistra aritmeticamente in un modo portatile, quindi aggiungere in c[1].)

+0

Come ho detto dopo, se si esegue il cast non firmato per il char firmato, si rischia di espandere il bit del segno. Meglio mascherare il risultato con 0x0000FFFF per essere sicuri che il bit del segno sia basso. –

+0

@ Mr.Gate, non sto "solo" scrivendo 'unsigned char' su' signed char'. Sto usando un cast di puntatori per reinterpretare il pattern di bit come 'signed char', quindi promuovendo a' int'. –

+1

La maggior parte dei compilatori ** non ignora ** le regole di aliasing. GCC genererà quasi sicuramente un codice che non riesce a fare ciò che vuoi a meno che tu non gli passi le opzioni speciali. –

2

Dipende di endianness. Qualcosa per big endian:

unsigned char x[2]; 
short y = (x[0] << 8) | x[1] 

Qualcosa per little endian:

unsigned char x[2]; 
short y = (x[1] << 8) | x[0] 
+1

* caratteri non firmati * –

+0

Non è probabile che funzioni su molti sistemi, in particolare dove '' char' 'è firmato ('x [0]' e 'x [1]' sarà esteso al segno, quindi se il il meno significativo è negativo, il byte superiore sarà impostato su tutti 1 per l'OR bit a bit). – caf

5

avvolgerli in un sindacato:

union { 
    unsigned char a[2]; 
    int16_t smt; 
} number; 

Ora dopo aver riempito l'array è possibile utilizzare questo come number.smt

+2

@VGE: la conversione 'short' in' int' è ben definita. Anche se raccomando di usare 'int16_t' invece di' short'. –

1

La soluzione portatile:

unsigned char c[2]; 
long tmp; 
int result; 

tmp = (long)c[0] << 8 | c[1]; 
if (tmp < 32768) 
    result = tmp; 
else 
    result = tmp - 65536; 

Ciò presuppone che i byte nell'array rappresentino un intero con segno di 16 bit, complemento a due, big endian. Se sono un numero intero di endian, basta scambiare c[1] e c[0].

(Nel caso altamente improbabile che si tratta di complemento a uno, utilizzare 65535 anziché 65536 come valore da sottrarre Sign-grandezza viene lasciato come esercizio per il lettore;.)

+0

Preferisco mascherare il risultato con 0x0000FFFF.Ciò garantisce che, anche se il bit del segno è espanso, si concede che il valore sia compreso tra 0x0000FFFF e 0. –

+0

@ Mr.Gate: non è necessario alcun mascheramento. Dato che 'c [0]' e 'c [1]' sono numeri positivi tra 0 e 255, 'tmp' è un numero positivo nell'intervallo da 0 a 65535. L'unico numero negativo viene prodotto nella sottrazione finale - non vi è alcuna possibilità dell'estensione di segno indesiderata. – caf

Problemi correlati