2010-11-17 11 views
8

Ho cercato questo sito per una risposta e ho trovato molte risposte al confronto firmato/non firmato, ma questo problema è che solo i parametri non firmati vengono confrontati, ma funziona comunque in modo divertente.non firmato diventa firmato nel confronto delle istruzioni if?

Il problema con il seguente codice è che il primo if -statment non si verifica ("ciao") dove è il secondo ("mondo"). Questo ho interpretato come il calcolo eseguito all'interno dello-if -statment genera un numero negativo ma lo stesso esatto calcolo fatto con il risultato salvato in una variabile non lo fa (anche se il risultato è stato salvato in una variabile firmata).

Il compilatore utilizzato è gcc 4.4.

unsigned short u16_varHigh; 
unsigned short u16_varLow; 
unsigned short u16_Res1; 
signed short s16_Res1; 

u16_varHigh = 0xFFFF; 
u16_varLow = 10; 

u16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected 
s16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected 

// Does not enter 
if((u16_varLow - u16_varHigh) > (unsigned short)5) 
{ 
printf("hello"); 
} 

// Does enter 
if((unsigned short)(u16_varLow - u16_varHigh) > 5) 
{ 
printf("world"); 
} 

Qualcuno può spiegare questo per me e forse trovare una soluzione per una correzione in modo che il primo if -affermazione funziona così?

+0

possibile duplicato (http [Domanda sul regole promozione integrale C.]: // StackOverflow .com/questions/2280663/question-about-c-integral-promotion-rules) – unwind

+3

Non sono d'accordo. Su argomenti simili, ma non duplicati. – Kos

risposta

4

Nell'espressione:

if((u16_varLow - u16_varHigh) > (unsigned short)5) 

(u16_varLow - u16_varHigh) sarà promosso a un int e valutare a -65.525. La soluzione per il tuo problema è di eseguire il cast su un tipo senza segno, come nel codice "Does enter".

Il motivo s16_Res1 = u16_varLow - u16_varHigh; restituisce 11 è che il risultato della sottrazione, -65525, non rientra in un corto.

+0

In realtà 'u16_varLow' e' u16_varHigh' sono promossi individualmente a 'int', prima della sottrazione. – caf

+0

Si tratta di due lanci individuali? Non verrà inserita la seguente istruzione if: u16_varHigh = 0xff00;
if (u16_varHigh <-5) ... La decisione di renderlo firmato dipende dalla sottrazione. Quindi confrontare un unsigned (con un bit alto impostato) sarà considerato non firmato, ma confrontare la differenza tra 2 unsigned e viene considerato firmato. Sembra sbagliato in qualche modo ... – Wilmer

+0

Vale anche la pena notare che '(unsigned short)' non ha alcun effetto (su una macchina a 32 bit). '(unsigned short) 5' è promosso a' int' prima di essere considerato come input per il confronto, se tutti i valori di 'unsigned short' rientrano in un' int'. Se lo hai fatto su un processore in cui short e int avevano la stessa larghezza, '(unsigned short) 5' avrebbe promosso a' unsigned', come sarebbe il lhs, e la condizione sarebbe vera. – greggo

1

Il primo, if((u16_varLow - u16_varHigh) > (unsigned short)5) non passerà mai, poiché (u16_varLow - u16_varHigh) restituisce un numero negativo, perché è considerato come un numero intero. Il secondo lancia lo stesso numero negativo, a corto non firmato, ecco perché passa.

Nota - sai che tutto questo dipende dalla piattaforma, giusto? La dimensione di short, int, ecc. Dipende dalla piattaforma di cemento.

+0

@Note: ne sono a conoscenza, ma ti ringrazio comunque (perché non ne ero a conoscenza, mi avresti risparmiato un sacco di lavoro) – Wilmer

2

Nelle altre risposte abbiamo visto che

u16_varLow - u16_varHigh 

per voi (con 16 bit short e 32 bit int) è equivalente a

(int)u16_varLow - (int)u16_varHigh 

e quindi il suo risultato è il valore -65525int . Così l'assegnazione

s16_Res1 = u16_varLow - u16_varHigh; 

è equivalente a

s16_Res1 = -65525; 

che nel tuo caso di 16 bit short cede "comportamento non definito". Sei sfortunato che il tuo compilatore decide di assegnare 11, invece. (Sfortunato perché penso che sia meglio fallire presto.)

Per contro il

u16_Res1 = -65525; 

è un'assegnazione valida dal u16_Res1 è di un tipo senza segno e aritmetica dei tipi senza segno è modulo l'appropriata potenza di due.

2

Nelle "normali conversioni aritmetiche", i tipi inferiori a int vengono promossi a int o unsigned int prima di essere utilizzati nella maggior parte delle espressioni. La regola è che se int può rappresentare tutti i valori del tipo più piccolo, viene promosso a int; altrimenti viene promosso a unsigned int. Questo è spesso considerato qualcosa di una verruca, perché in molti casi causa i valori unsigned char e unsigned short da promuovere a int.

Questo è esattamente quello che stai vedendo - u16_varLow e u16_varHigh e (unsigned short)5 sono tutti promossi al int prima della sottrazione e confronto, che poi accade utilizzando int. Se si desidera essere certi che un'espressione utilizzerà aritmetica non firmato, è necessario farlo in unsigned int, nonunsigned short:

if(((unsigned)u16_varLow - (unsigned)u16_varHigh) > 5U)