2010-10-22 14 views

risposta

6

già il punto di partenza è problematica:

char c = 0x80; 

Se (come apparentemente nel tuo caso) char è un tipo firmato, si sta assegnando il numero intero costante 128 a un tipo che è garantito solo per contenere i valori up a 127. Il tuo compilatore può quindi scegliere di darti qualche valore definito di implementazione (-128 nel tuo caso, suppongo) o di emettere un errore di intervallo.

Quindi si sta eseguendo uno spostamento a sinistra su quel valore negativo. Questo dà un comportamento indefinito. In totale si hanno diverse scelte implementative definito più un comportamento indefinito che determinano il risultato:

  • signedness di char
  • la scelta di come convertire 128 a signed char
  • la larghezza della char
  • la rappresentazione segno di int (ci sono tre possibilità)
  • la scelta su come implementare (o meno) lo spostamento a sinistra su negativo int

Potrebbe essere un buon esercizio per cercare tutti questi casi e per vedere quali potrebbero essere i diversi risultati.

In sintesi alcune raccomandazioni:

  • scegliere un costante appropriata per inizializzare una variabile aritmetica
  • non fare con la pianura char
  • non facciamo spostamento a sinistra sui tipi firmati
+0

Grazie Jens signore per la risposta. –

+0

Il primo paragrafo della spiegazione è sbagliato e può ingannare qualcuno inesperto. "char c = 0x80;" va bene, proprio come "int c = 0xFFFFFFFF" va bene, ma la parte che non va bene presuppone che 0x80 sia 128 quando char può essere firmato (intervallo da -128 a 127, non da 0 a 255) –

+0

@ B.Nadolson , Non penso che sia fuorviante. La costante '0x80' è di tipo' int' e ha valore '128'.Questo tipo e valore sul RHS vengono determinati per primi, quindi quel tipo e valore viene convertito per adattarsi al tipo sul LHS. Cercando di inizializzare una variabile possibilmente firmata con un valore che non si adatta al tipo è un errore semantico. –

18

char può essere firmato sulla piattaforma, nel qual caso 0x80 rappresenta -128 (presupponendo il complemento a due).

Quando un char viene utilizzato come operando con l'operatore <<, viene promosso a int (fermo -128). Quindi, quando applichi lo spostamento a sinistra, ottieni -256. Tecnicamente, il passaggio dei valori negativi è definito dall'implementazione indefinito, ma ciò che viene visualizzato è un comportamento tipico.

+0

Non penso che la tua affermazione riguardi la promozione di 'int' sia corretta. Gli operatori di turno non fanno promozione, il tipo di risultato è il tipo a sinistra. –

+0

@Jens: Per essere onesti, ho solo lo standard C99 davanti a me. Ma dice nella sezione 6.5.7: "Le promozioni intere sono eseguite su ciascuno degli operandi." –

+0

oops, a destra. Quindi integrerò anche quello nella mia risposta :) –

3

c assegnato 0x80. Supponendo byte da 8 bit, il suo valore in rappresentazione binaria è 10000000. Apparentemente, sulla tua piattaforma, char è un tipo firmato. Quindi, 0x80 (ad esempio 10000000) corrisponde a -128.

Quando << viene applicato a un valore char, viene promosso a int e il segno viene mantenuto. Quindi, quando spostato una volta a sinistra, con numeri interi a 32 bit, diventa 11111111111111111111111100000000 (complemento a due) che è -256.

+0

La promozione di 'int' non ha nulla a che vedere con' printf' in questa istanza; è dovuto al '<<'. Inoltre, questa non è la rappresentazione di -256 nel complemento a uno o a due. –

+0

@ Oli Grazie per la correzione. –

+0

Grazie mille Oli e Sinan. Ho capito la logica .. –

0

Mi chiedo perché il compilatore non si lamenta di un avviso che 0x80 non si adatta al char, che sulla piattaforma può rappresentare solo valori da -0x80 a 0x7F.

Prova questo pezzo di codice:

#include <stdio.h> 
#include <limits.h> 
#include <stdlib.h> 

int main() { 
     printf("char can represent values from %d to %d.\n", CHAR_MIN, CHAR_MAX); 
     return EXIT_SUCCESS; 
} 

La vostra situazione è chiamata overflow.

1

Solo una nota a margine. Da una prospettiva dal basso verso l'alto, lo spostamento bit-saggio (e il mascheramento) si basa sulla lunghezza della parola di un'architettura (espressa in bit). La lunghezza di una parola, varia dall'architettura all'architettura.

See this Wiki page for word lengths by architecture

Se si conosce la lunghezza di parola dell'architettura bersaglio, si può usare bit spostamento di moltiplicazione e divisione (in alcuni casi), più veloce rispetto all'utilizzo operandi.

See this Wiki page for interesting diagrams of bit-shifting

Poiché codice bit-shifted è architettura dipendente, non si può assumere una parte specifica del codice bit spostata funziona allo stesso modo dall'architettura all'architettura. Tuttavia, una volta acquisita familiarità con l'idea di lunghezze di parole diverse per architetture diverse, il bit-shifting diventa meno misterioso e più prevedibile.

Per fortuna, oggi abbiamo lunghezze di parola di 8, 16, 32 e 64 bit e lunghezze di carattere esclusivamente di 8 bit. Nei tempi dell'antica informatica, un'architettura poteva avere una lunghezza di parola 12, o 15, o 23 bit (ecc., Fino alla nausea).

+0

Grazie Mike signore per aver condiviso questa informazione. Tutti voi avete una grande conoscenza. –

Problemi correlati