2011-09-22 3 views
15

Sul mio compilatore, il seguente pseudo codice (valori sostituiti con binario):spostamento a destra e firmato intero

sint32 word = (10000000 00000000 00000000 00000000); 
word >>= 16; 

produce una word con un campo di bit che assomiglia a questo:

(11111111 11111111 10000000 00000000) 

La mia domanda è, posso fare affidamento su questo comportamento per tutte le piattaforme e i compilatori C++?

risposta

23

dal seguente link:
INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand

Codice Non conforme Esempio (sposta a destra)
Il risultato di E1 >> E2 è E1 posizioni di destra in differita E2 bit. Se E1 ha un tipo senza segno o se E1 ha un tipo firmato e un valore non negativo, il valore del risultato è la parte integrante del quoziente di E1/2 E2. Se E1 ha un tipo firmata e un valore negativo, il valore risultante è attuazione definito e può essere sia un aritmetica (firmato) spostamento:
Arithmetic (signed) shift
o un logico shift (senza segno):
Logical (unsigned) shift
Questo esempio di codice non conformi non riesce a verificare se l'operando destro è maggiore o uguale alla larghezza dell'operando sinistro promosso, consentendo un comportamento indefinito.

unsigned int ui1; 
unsigned int ui2; 
unsigned int uresult; 

/* Initialize ui1 and ui2 */ 

uresult = ui1 >> ui2; 

presumere che uno spostamento a destra è implementato come aritmetica (firmati) spostamento o un logico (senza segno) spostamento può anche portare a vulnerabilità. Vedere la raccomandazione INT13-C. Use bitwise operators only on unsigned operands.

+1

Non vi era alcuna raccomandazione che si concentri effettivamente su questo problema? Perché basato sul nome di quella regola, non si applica qui ... stai solo citando alcune delle informazioni di base fornite. –

12

No, non puoi fare affidamento su questo comportamento. Il corretto spostamento delle quantità negative (che presumo il tuo esempio sta trattando) è definito dall'implementazione.

+0

Ok, è giusto. Mi chiedo comunque, se il compilatore crea un binario che usa questo metodo, funzionerebbe come previsto nella maggior parte dell'hardware, almeno? –

+4

Se si compila qualcosa per una determinata architettura, si suppone che funzioni allo stesso modo su tutte le implementazioni di tale architettura. x86, ad esempio, ha diverse operazioni di spostamento per i cambiamenti di estensione di segno e di non-segno, ed è il compilatore che decide quale usare. Probabilmente non funzionerà affatto (leggi: * qualsiasi cosa *, non solo questo comportamento) su altre architetture. –

+0

Questo è orribile ... – Claudiu

3

Gli interi AFAIK possono essere rappresentati come grandezza del segno in C++, nel qual caso l'estensione del segno si riempirebbe di 0 s. Quindi non puoi fare affidamento su questo.

+0

Hai ragione. Lo standard fa alcuni requisiti che fanno di due complementi la rappresentazione ottimale, ma in generale, gli interi con segno possono essere rappresentati in qualsiasi modo l'implementazione vuole. –

6

In C++, n. È implementazione e/o dipendente dalla piattaforma.

In alcune lingue, sì. In Java, ad esempio, l'operatore >> è definito con precisione per riempire sempre usando il bit più a sinistra (preservando così il segno). L'operatore >>> si riempie usando 0s. Quindi, se vuoi un comportamento affidabile, una possibile opzione sarebbe quella di passare a una lingua diversa. (Anche se ovviamente, questa potrebbe non essere un'opzione a seconda delle circostanze.)