2015-12-22 32 views
7

Sto provando a confrontare il primo carattere di una stringa e una costante esadecimale per determinare il tipo di dati. Ma ogni volta fallisce. Qualcuno può spiegare perché sotto il confronto fallisce sempre.Il confronto fallisce sempre con char e costante

char charray[] = {0xAA, 0x00, 0x02}; 
char ch = charray[0]; 
if (0xAA == ch) 
{ 
    printf("Equal\n"); 
} 

risposta

8

Il problema è qui:

char charray[] = {0xAA, 0x00, 0x02}; 

Il tipo char ha signedness implementazione definita, il che significa che in alcuni sistemi sarà equivalente a signed char. Un signed char può solo memorizzare valori fino a 0x7F e l'MSB verrà trattato come un bit di segno. Questo è ciò che accade nel tuo caso, 0xAA viene convertito in un valore firmato di -86 (è definito dall'implementazione quale valore ottiene, sto assumendo il complemento a due).

Il segno viene quindi mantenuto nell'espressione 0xAA == ch, perché ch viene quindi promosso per digitare int e il segno viene mantenuto. Significa che comparirai effettivamente a 0xAA == -86 che è falso.

Per evitare errori di questo tipo, utilizzare sempre uint8_t quando si effettua qualsiasi forma di aritmetica a livello di byte.

1

0xAA è un int letterale. char potrebbe essere firmato o non firmato sul tuo sistema. Lo standard C consente entrambi.

In 0xAA == ch, il ch viene promosso un tipo int, e il confronto viene valutato come 0.

1
if (0xAA == ch) 

Supponendo char è signed char (Comportamento char come signed char o unsigned char dipende dall'implementazione in C), char viene promosso a int nell'espressione == e in un sistema a 32 bit che si sta effettivamente confrontando:

if (0xAA == 0xFFFFFFAA) 

che è falso.

Un modo per evitare l'estensione del segno è quello di gettare l'operando di destra unsigned char:

if (0xAA == (unsigned char) ch) 

Ma il migliore è semplicemente quello di utilizzare unsigned char quando si dichiara la matrice.

+0

No, in realtà sta confrontando '0xAA == -86'. Non necessariamente la stessa cosa di '0xAA == 0xFFFFFFAA', a seconda di come le promozioni implicite risultano sul sistema specifico. – Lundin

+0

@Lundin se vuoi essere schizzinoso, in realtà sta confrontando '0xAA == (signed char) 0xAA' che è persino diverso dal momento che la conversione è definita dall'implementazione. – ouah

+0

Il mio punto è: finché l'operando di sinistra (il letterale int) è un 'int', il char passerà attraverso la promozione intera (la regola di promozione intera) e rimarrà firmato. Ma se il letterale era un tipo senza segno, ci sarebbe anche il bilanciamento (solite conversioni aritmetiche) e l'operando di destra verrebbe convertito anche in tipo senza segno. Nel qual caso si finirebbe per essere uguale a '0xFFFFFFAAu'. Ma questo non accade in questo specifico esempio. – Lundin

Problemi correlati