2009-09-12 14 views
8

Non capisco questo!non firmato lungo 0 <-1?

#include <stdio.h> 

int main() 
{ 
    unsigned short t1 = 0, t2 = 0; 

    if(t1 < t2-1) 
     printf(" t1 < t2-1\n"); 

    unsigned long s1 = 0, s2 = 0; 

    if(s1 < s2-1) 
     printf(" s1 < s2-1\n"); 
} 

questo si traduce in:

s1 < s2-1 

O entrambi dovrebbero fallire o entrambi non. Ho provato questo con gcc 4 & 4.2

+0

~ nairboon: spero che non ti dispiaccia la modifica. Il codice che ho sostituito con il tuo è funzionalmente lo stesso, ma può essere copiato/incollato in un editor e compilato senza modifiche. –

+1

Si noti che questo risultato non è garantito come risultato. Sulle macchine in cui int memorizza lo stesso intervallo di valori più breve (credo che le macchine a 16 bit, penso), vedrete l'output per entrambi i se, perché la promozione verrà convertita in unsigned int, anziché in int. –

risposta

12

Il linguaggio C esegue le "conversioni aritmetiche usuali" per molti operatori - il le conversioni sono delineate in 6.3.1.8 dello standard C99. Per gli operandi integrali, vengono eseguite le prime promozioni e questo è ciò che sta causando il problema. Le promozioni sono illustrate nel 6.3.1.1 (aritmetiche operandi/booleani, caratteri e numeri interi), che dice tra l'altro:

Se un int può rappresentare tutti i valori del tipo di originale, il valore viene convertito in un int; in caso contrario, viene convertito in un int unsigned. Queste sono chiamate promozioni intere. Tutti gli altri tipi sono invariati dalle promozioni intere.

Le promozioni sono applicati solo a oggetti o espressioni con un tipo intero con un rango inferiore int e unsigned int (o bitfields).

Quindi nel tuo Exression:

t1 < t2-1 

anche se le variabili sono unsigned short sono promossi a int, dal momento che sulla vostra piattaforma int può rappresentare tutti i valori di unsigned short. Pertanto, l'espressione viene valutata utilizzando i tipi int e non si verifica un underflow: la parte dell'espressione t2-1 termina come 1 negativo.

Nell'espressione:

s1 < s2-1 

i tipi unsigned long non vengono promossi, perché hanno un più alto 'rango' di int/unsigned int, quindi l'espressione viene valutata utilizzando l'aritmetica non firmato (con l'underflow dal sottrazione), e il s2-1 sottoespressione restituisce un numero molto grande, non negativo 1.

come litb indicato in un commento, se la piattaforma avesse int implementato come un tipo a 16 bit (che è consentito - MS-DOS per esempio), il pro movimento di unsigned short invece di unsigned int anziché int, poiché un int non è in grado di rappresentare tutti i valori di unsigned short (unsigned short deve essere di almeno 16 bit). In tal caso, entrambe le istruzioni if verrebbero considerate true.

13

Non sono sicuro, ma ho il sospetto che l'espressione t2-1 si sia automaticamente ampliata in un valore int. Non ho lo standard c qui le esatte regole di conversione, ma credo che i tipi più piccoli di int vengano automaticamente ampliati.

+3

+1, in un'espressione aritmetica, gli oggetti di tipo short (firmato/non firmato) e (firmato/non firmato /) sono * promossi * a int. – avakar

+1

Questa risposta sarebbe molto meglio se tu dicessi che ** t2' ** è convertito in int, non ** 't2-1' ** (in modo che sia chiaro che la conversione avviene * prima * della sottrazione), comunque. –

3

Le coercizioni di C, come state scoprendo, non sono sempre ovvie, ogni volta che operate tra tipi diversi. t2 è u16, 1 è int (presumibilmente a 32 bit), quindi t2-1 è esattamente una "operazione tra tipi diversi" e genera una coercizione globale a int (poiché è "più lungo" di u16 ...). Successivamente, poiché s2 e 1 sono entrambi a 32 bit (sebbene di diversa firma), la coercizione globale è quella di unsigned long. Quindi, le dimensioni dei tipi coinvolti aiutano a determinare la firma della coercizione globale.

mi consiglia di evitare gli mixed-signedness operazioni (tramite fusione o la notazione letterale speciale per letterali quali 1 che altrimenti avranno int tipo e rendere la vita potenzialmente complicato e il tuo codice potenzialmente portabile (e idealmente anche mixed-size!); -).

0

-1 è rappresentato come tutti gli 1. Pertanto, quando interpretato come unsigned, il suo valore è 2^32-1, che è chiaramente maggiore di 0. Immagino che il primo confronto venga espanso per eseguire aritmetica con segno a 32 bit (forse perché "1" è un firmato int).

Si noti che il seguente sarà arrivare al printf, perché il confronto è ora fatto in 16 bit di spazio non firmato di nuovo:

u32 temp = t2 - 1; 
if(t1 < temp) 
    printf(" t1 < t2-1\n"); 
+4

Il letterale 1 (di tipo 'int') viene convertito in' unsigned long' prima della sottrazione. Poiché l'aritmetica sui tipi senza segno viene sempre eseguita modulo '2^k', per k specifico di tipo specifico, il risultato è' 2^k-1'. La rappresentazione di -1 non è coinvolta (e non è necessario che siano tutte su alcune architetture). – avakar

+0

La rappresentazione di -1 è implicata nello spiegare la seconda parte: perché 0 <-1 in caratteri non firmati. – Yuliy

+0

No, non lo è. Come dice avakar, '-N' -> unsigned è un'operazione puramente matematica, che calcola semplicemente' UINT_MAX + 1 - N'. Nessuna rappresentazione è invocata da nessuna parte. –

Problemi correlati