2014-05-05 13 views
5

Desidero memorizzare uno unsigned char in un char mediante uno spostamento. Mentre i due tipi di dati hanno la stessa lunghezza (1 byte sulla mia macchina), mi sarei aspettato il codice seguente al lavoro:Inserire un carattere `unsigned` in un` char`

#include <iostream> 
#include <cstring> 
#include <cstdio> 

using namespace std; 

int main() { 

     printf ("%d\n", sizeof(char)); 
     printf ("%d\n", sizeof(unsigned char)); 

     unsigned char test = 49; 
     char testchar = (char) (test - 127); 
     printf ("%x\n", testchar); 

     return 0; 
} 

ma non è così. In particolare, ho ricevuto il seguente output:

1 
1 
ffffffb2 

che suggerisce che il char sono stati trasformati int. Qualcuno ha una spiegazione e, si spera, una soluzione?

+0

Immagino che "si interrompa" a causa di% x. Hai provato% d? – Jasper

+0

O printf% x o% d su tutto, qui viene visualizzato il valore decimale ed esadecimale. – DrakaSAN

+0

Non capisco assolutamente perché stai sottraendo 127, e penso che sia un vero peccato che non ti sia preso la briga di spiegare questo approccio nella tua domanda. –

risposta

5

%x è un identificatore per un 4 byte int. Per stampare un byte char utilizzare %hhx.

printf tipizza i suoi argomenti in base agli specificatori di formato passati. Ecco perché testchar è stato promosso a int.

5

printf è una funzione di argomento variabile e, di conseguenza, gli argomenti sono soggetti alle regole di promozione predefinite. In questo caso, il tuo char viene promosso a un int, e in quel processo viene esteso il segno. Il comp interno a 2 di 4 byte con il modello binario 0xffffffb2 è -78. Stampalo come carattere con lo specificatore %hhx.

Vedi anche Which integral promotions do take place when printing a char?

2

Quello che succede è !!!!

1) unsigned char test = 49; // viene assegnato il valore esadecimale 31

2) char testchar = (char) (test - 127); // 49-127 = -78 ie; 0xb2 (come unsigned), convertendolo in signed char risultati F imbottitura prima b2 per indicare come negativo

3) printf ("%x\n", testchar); // Dal %x è un identificatore per un int 4 byte (come @ Non ti preoccupare bambino detto) ffffffb2, 4 byte di uscita è ottenuto

in modo da provare come da @ non ti preoccupare Bambino detto

1

%x è solo per la stampa unsigned int, tuttavia si fornisce un char.

L'utilizzo di %x con un valore negativo di char causa un comportamento non definito.

A parte: Le specifiche C standard di printf non sono particolarmente chiare; alcuni ritengono che il passaggio di qualsiasi cosa eccetto esattamente un unsigned int causi un comportamento non definito. Altri (me compreso) ritengono che sia corretto passare argomenti che non sono specificatamente unsigned int, ma dopo le promozioni degli argomenti predefiniti, digitare int con un valore non negativo.Lo standard garantisce che gli int non negativi abbiano la stessa rappresentazione dello unsigned int con lo stesso valore.


Alcune delle altre risposte suggeriscono %hhx, ma che non è niente di meglio di %x. Lo standard (su un'interpretazione ragionevole) specifica che %hhx può essere utilizzato solo con un argomento unsigned char e che %hhd può essere utilizzato solo con un argomento signed char. Non c'è in realtà alcun modificatore per il semplice char.

In entrambi i casi, è possibile utilizzare lo printf per convertire i valori negativi in ​​rappresentazioni positive in modo ben definito. È necessario convertire autonomamente l'argomento e quindi utilizzare un identificatore di formato corrispondente. In questo caso:

printf ("%hhx\n", (unsigned char)testchar); 

sarebbe una opzione. IMO %x potrebbe essere utilizzato qui, ma come detto sopra, alcuni non sono d'accordo.


NB. L'identificatore di formato errato viene utilizzato in printf ("%d\n", sizeof(char)); e nella riga successiva. Lo specificatore per size_t è %zu. Così si potrebbe usare sia %zu, o lanciare l'argomento int, o meglio ancora:

printf("1\n"); 
0

mi sarei aspettato il seguente codice al lavoro:

E non lo farà.

Ignorando i problemi che altre persone hanno evidenziato con il modo in cui si è la stampa del carattere, non vi è alcuna garanzia nello standard che il codice funzioni. Perché?

Perché char non deve essere firmato. Se char è signed o unsigned dipende dall'implementazione. Alcune implementazioni rendono firmato char, altri lo rendono non firmato.

In questo modo, non è possibile garantire che (char) (test - 127) generi un valore che può essere rappresentato da char.

C++ (14) consente la conversione senza perdita tra unsigned char e char. Lo stadnard dice (3.9.1/1):

Per ogni valore i di tipo unsigned char nel campo da 0 a 255 compresa, esiste un valore j di tipo char tale che il risultato di una conversione integrale (4.7) da i a char è j, e il risultato di una conversione integrale da j a unsigned char è i.

Problemi correlati