2010-09-08 6 views
8
signed int x= -5; 
unsigned int y=x; 

qual è il valore di y? e come?Valori non firmati e firmati in C (qual è l'output)

+5

Quando si è tentato questo, che cosa hai visto? –

+4

@KennyTM, non è stata definita l'implementazione; il casting da un int unsigned a un int firmato che non può rappresentarlo è definito dall'implementazione, ma il contrario (firmato -> unsigned) è ben definito. – bdonlan

+2

@bdonlan: 'UINT_MAX' * è * implementazione definita. – kennytm

risposta

-1

y = 0xfffffffb è la rappresentazione binaria di -5 (complemento a due)

+0

Potrebbe per favore spiegarlo di più .... –

+1

Il risultato non dipende da alcuna "rappresentazione binaria". Il risultato è dettato dai requisiti dello standard linguistico. E lo standard è piuttosto esplicito in questo caso. – AnT

+0

@AndreyT. Per essere onesti, sebbene non sia affermato in questo modo, è certamente vero che il complemento a 2 -> conversione senza segno ha lo stesso schema di bit (penso che lo standard C++ ne citi di passaggio, non ricordo se lo standard C lo fa). La descrizione di Philibert è equivalente alla definizione nello standard: puoi convertire firmato -> senza segno elaborando la rappresentazione del complemento a 2 del valore firmato, quindi leggendolo come un valore senza segno. Non ha mai detto che è così che l'implementazione effettivamente lo fa (anche se senza dubbio le implementazioni del complemento 2 lo fanno). –

16

Essa dipende dal valore massimo della unsigned int. Tipicamente, un unsigned int è 32 bit lungo, in modo che il UINT_MAX è 2 − 1. Lo standard C (§ 6.3.1.3/2) richiede una firmata → conversione unsigned essere eseguita come

Altrimenti, se il nuovo tipo non è firmato, il valore viene convertito aggiungendo o sottraendo ripetutamente un valore superiore al valore massimo che può essere rappresentato nel nuovo tipo finché il valore non si trova nell'intervallo del nuovo tipo.

Così y = x + ((2 − 1) + 1) = 2 − 5 = 4294967291.


In una piattaforma 2's complement, che la maggior parte delle implementazioni sono al giorno d'oggi, y è anche la stessa rappresentazione in complemento a 2 di x.

-5 = ~ 5 + 1 = 0xFFFFFFFA + 1 = 0xFFFFFFFB = 4294967291.

2

Il valore di y è UINT_MAX - 5 + 1, cioè UINT_MAX - 4.

Quando si converte il valore intero con segno nel tipo senza segno, il valore viene ridotto modulo 2^N, dove N è il numero di bit che generano valore nel tipo senza segno. Questo vale per i valori firmati sia negativi che positivi.

Se si esegue la conversione di tipo firmato per tipo unsigned delle stesse dimensioni, quanto sopra significa che i valori positivi firmati rimangono invariati (+5 viene convertito in 5, per esempio) e valori negativi vengono aggiunti al MAX + 1, dove MAX è la valore massimo del tipo senza segno (-5 viene convertito in MAX + 1 - 5).

4

Dalla serie C99:

6.3.1.3 firmata e interi senza segno

  1. Quando un valore di tipo intero viene convertito in un altro tipo intero diverso _Bool, se il valore può essere rappresentato dal nuovo tipo, non è cambiato.
  2. Altrimenti, se il nuovo tipo è senza segno, il valore viene convertito da ripetutamente aggiungendo o sottraendo un superiore al valore massimo che può essere rappresentato nel nuovo tipo finché il valore è nell'intervallo del nuovo tipo . 49)

49) Le regole descrivono aritmetica sul valore matematico, non il valore di un determinato tipo di espressione.

Quindi guarderai, efficacemente, y = x + UINT_MAX + 1.

Ciò significa che la rappresentazione a due complementi viene utilizzata invariata come numero intero senza segno, il che lo rende molto veloce sulla maggior parte dei computer moderni, poiché utilizzano il complemento a due per gli interi con segno.

+3

Ne manca uno: UINT_MAX è 2^N-1. –

+0

Non completamente corretto. La formula corretta è 'y = x + UINT_MAX - 1'. – AnT

+1

@AndreyT: in realtà la formula corretta è 'y = x + UINT_MAX + 1'. – kennytm

1

valori Firmata sono tipicamente memorizzati come qualcosa che si chiama two's complement:

Due di numeri complemento sono un modo per codificare i numeri negativi in ​​binario ordinario, in modo tale che oltre funziona ancora. L'aggiunta di -1 + 1 dovrebbe essere uguale a 0, ma l'aggiunta ordinaria fornisce il risultato di 2 o -2, a meno che l'operazione non richieda una speciale notifica del bit del segno e esegua invece una sottrazione. Il complemento a due produce la somma corretta senza questo passaggio aggiuntivo.

Ciò significa che la rappresentazione effettiva dei numeri -5 e 4.294.967,291 mila in memoria (una parola a 32 bit) sono identiche, per esempio: 0xFFFFFFFB o 0b11111111111111111111111111111011. Così, quando si fa:

unsigned int y = x; 

Il contenuto di x viene copiato pari pari, cioè bit a bit a y. Ciò significa che se si controllano i valori non elaborati nella memoria di x e , saranno identici. Tuttavia, se lo fai:

unsigned long long y1 = x; 

il valore di x sarà segno-prorogato, prima di essere convertito in un unsigned long long. Nel caso comune quando long long è 64 bit significa che y1 equivale a 0xFFFFFFFFFFFFFFFB.

È importante notare cosa succede quando si esegue il casting su un tipo più grande. Un valore firmato che viene convertito in un valore firmato più grande verrà esteso al segno. Ciò non avviene se il valore sorgente è senza segno, es .:

unsigned int z = y + 5; 
long long z1 = (long long)x + 5; // sign extended since x is signed 
long long z2 = (long long)y + 5; // not sign extended since y is unsigned 

z e z1 sarà uguale 0 ma z2 non. Questo può essere risolto casting del valore di firma prima espansione esso:

long long z3 = (long long)(signed int)y + 5; 

o analogicamente se non desidera che l'estensione del segno si verifichi:

long long z4 = (long long)(unsigned int)x; 
+1

Ma la domanda riguarda la conversione in * unsigned * type. Tuttavia, nella risposta stai solo citando le conversioni ai tipi * firmati *. – AnT

+0

Mi permetto di dissentire, anche se focalizzo la mia risposta in qualche modo sulle conversioni sui tipi firmati poiché è lì che ci sono i draghi. Inoltre, non penso che la mia risposta meriti il ​​downvote ma sono di parte. –

+0

+1: per "complemento a due", anche se in realtà la dicitura evasiva di C99 fornisce una definizione che funzionerebbe anche con un compilatore che userebbe dire BCD.Mi chiedo comunque che un compilatore C di questo tipo esista, finché non si è dimostrato sbagliato credo che tutti i compilatori C attualmente esistenti usino il complemento a due. – kriss