2012-06-04 20 views
7

La lingua che uso è C. Il tipo di x e n è int.La differenza tra ~ (x-1) e ~ x + 1 quando x = 0x80000000

Ho un codice di linea come seguendo

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

Esso mostra il valore di x, n e due metodi di spostamento n bit del numero complemento di x. Quando x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000, tuttavia quando si spostano questi due per n bit, i risultati sono diversi.

btw, se ho cambiato 0xffffffff a ~ 1 + 1 (che significa ~ (x + (~ 1 + 1)), il risultato è lo stesso ~ x + 1

Mi chiedo perché quello che è successo. Grazie .

+0

[Is “(uint16_t) -1" Portable C Codice?] (Http://embeddedgurus.com/barr-code/2011/06/is-uint16_t-1-portable-c-code/) – Lundin

+0

@Lundin Quell'articolo è sbagliato. '(uint16_t) -1' ** è ** garantito dallo standard per produrre' 0xFFFF' se l'implementazione fornisce quel tipo in 'stdint.h'. (Naturalmente, nulla è garantito se è il tuo typedef.) Non c'è ambiguità, i tipi a larghezza fissa non devono avere bit di riempimento, quindi non è nemmeno limitato ai bit di valore (beh, lo è, dato che lì sono solo bit di valore in 'uintN_t'). –

risposta

4

La risposta ora cancellata da Pavan Manjunath ha avuto la risposta corretta per un caso, supponendo che lo int sia come al solito un tipo a 32 bit. L'intero costante

0xffffffff 

ha il valore 2^32 - 1 e che non è rappresentabile da un int, ma è rappresentabile come unsigned int. Quindi il suo tipo è unsigned int (6.4.4.1). Quindi x viene convertito unsigned int per l'aggiunta e

((~(x+0xffffffff))>>n) 

valutata come

((~(0x80000000u + 0xffffffffu)) >> n) 
((~0x7fffffffu) >> n) 
(0x80000000u >> n) 

con il valore 2^(31-n) se 0 <= n < 32 (è un comportamento indefinito se n è al di fuori di tale intervallo).

Per l'altro caso, la risposta di ouah è corretto, quando x = 0x80000000 è un int, ~0x8000000 = 0x7fffffff = INT_MAX e INT_MAX + 1 è comportamento non definito come integer overflow firmato.

Tuttavia, un comportamento comune è il wrap-around, quindi il risultato dell'aggiunta è il numero intero con segno 0x80000000 e lo spostamento a destra degli interi negativi è un comportamento definito dall'implementazione (6.5.7). Comune sta spostando con estensione del segno, che produce il risultato -2^(31-n), che poi viene interpretato come unsigned int con il valore 2^32 - 2^(31-n) dallo specificatore printf conversione %x.

+0

è ~ 0 il con o senza segno ... – shirley

+0

'0' è rappresentabile come un' int', in modo che il tipo di '~ 0 'è' int' troppo. –

1

Quando x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000,

in un sistema con 32 bit int (supponendo x è di tipo int) e la rappresentazione firmata complemento a due, questa espressione:

~x+1 

è un comportamento non definito. x = 0x80000000 significa ~x == 0x7FFFFFFF == INT_MAX e INT_MAX + 1 è un comportamento non definito. Quindi ~x + 1 può essere 0x80000000 o qualsiasi altra cosa.

Questa espressione:

~(x+0xffffffff) 

invece è definito (0xffffffff è unsigned int in C) ed è uguale a 0x80000000. In realtà è definito perché 0xffffffff è unsigned int e gli interi senza segno non eccedono mai nel senso dello standard C.

Ciò significa che questa affermazione:

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

invoca comportamento non definito e non ha senso confrontare entrambi i risultati.

0

(Supponendo sizeof (int) è 4 ;, cioè valore con segno a 32 bit). 0x80000000; // -2147483648 che è più piccola possibile negativo int 0xFFFFFFFF // è -1

Aggiungendo le proposte provoca un 'involucro intorno' da negativo a positivo 0x7FFFFFFF è la somma dei due (utilizzando int aritmetica), che è 2147483647

Utilizzando l'operatore '~' su 0x7FFFFFFF rendimenti un po 'completent-saggio, o 0x80000000

Se si inizia con un valore int e sottrarre 1 da esso (o si aggiunge 1 ad esso, non è così importa) abbastanza volte, lo farai capovolgere il suo segno. Questo è un problema di base con l'aritmetica usando una precisione fissa.

Nel tuo caso, non puoi aspettarti di mischiare operatori aritmetici e bit per bit firmati senza essere molto attento a questo caso limite.

Si noti inoltre un'asimmetria quando si utilizza l'aritmetica del complemento a 2: c'è un numero negativo in più rispetto al positivo (perché è necessario rappresentare zero, che lascia un numero dispari di altre rappresentazioni di bit per il resto dei valori).

Problemi correlati