2015-09-01 23 views
5

Ho il seguente semplice programma che utilizza un'unione per la conversione tra un intero a 64 bit e la corrispondente matrice di byte:C/C++ Convertire un intero a 64 bit char matrice

union u 
{ 
    uint64_t ui; 
    char c[sizeof(uint64_t)]; 
}; 

int main(int argc, char *argv[]) 
{ 
    u test; 
    test.ui = 0xabcdefLL; 
    for(unsigned int idx = 0; idx < sizeof(uint64_t); idx++) 
    { 
     cout << "test.c[" << idx << "] = 0x" << hex << +test.c[idx] << endl; 
    } 
    return 0; 
} 

Quello che ci si aspetterebbe come output è:

test.c[0] = 0xef 
test.c[1] = 0xcd 
test.c[2] = 0xab 
test.c[3] = 0x89 
test.c[4] = 0x67 
test.c[5] = 0x45 
test.c[6] = 0x23 
test.c[7] = 0x1 

Ma quello che in realtà ottengo è:

test.c[0] = 0xffffffef 
test.c[1] = 0xffffffcd 
test.c[2] = 0xffffffab 
test.c[3] = 0xffffff89 
test.c[4] = 0x67 
test.c[5] = 0x45 
test.c[6] = 0x23 
test.c[7] = 0x1 

sto vedendo questo su Ubuntu LTS 14.04 con GCC.

Ho cercato di capire da un po 'di tempo. Perché i primi 4 elementi dell'array char vengono visualizzati come numeri interi a 32 bit, con 0xffffff aggiunto a loro? E perché solo i primi 4, perché non tutti loro?
È interessante notare che quando uso la matrice per scrivere su un flusso (che era lo scopo originale dell'intera cosa), vengono scritti i valori corretti. Ma confrontare l'array char con char porta ovviamente a problemi, poiché i primi 4 caratteri non sono uguali a 0xef, 0xcd e così via.

+0

cast come '(char *)' e quindi leggere 4 byte ...? – SteJ

+0

Nessun cambiamento. Inoltre, posso sempre mascherare il carattere con 0x000000ff per ottenere i valori previsti. Sono solo interessato alla ragione di questo comportamento. – tickferno

+2

Apparentemente la tua implementazione ha firmato caratteri. La promozione di interi normale verrà firmata in estensione. – ewd

risposta

3

Utilizzare char non è la cosa giusta da fare poiché potrebbe essere signed o unsigned. Utilizzare unsigned char.

union u 
{ 
    uint64_t ui; 
    unsigned char c[sizeof(uint64_t)]; 
}; 
+0

Questo lo risolve. Il problema ora è che scrivere la matrice su un flusso dà degli errori dato che gli stream accettano solo 'char *' e non 'char unsigned * 'in più non mi piace usare' reinterpret_cast' tutto il tempo ... – tickferno

+1

@tickferno, se hai bisogno di aiuto, per favore pubblica un'altra domanda che risolva specificatamente il problema di streaming. –

0

E 'unsigned char vs char firmato e la sua fusione a intero

1

Utilizzare uno unsigned char o utilizzare test.c[idx] & 0xff per evitare di estensione del segno quando un char value > 0x7f viene convertito in int.

0

Il plus unario fa sì che il char per essere promosso a un (promozione integrale) int. Poiché hai firmato i caratteri, il valore verrà utilizzato come tale e gli altri byte lo rifletteranno.

Non è vero che solo i quattro sono interi, sono tutti. Semplicemente non lo vedi dalla rappresentazione poiché gli zeri iniziali non sono mostrati.

O utilizzare unsigned char s o & 0xff per la promozione per ottenere il risultato desiderato.

2

char viene promosso a int a causa dell'operatore unario anteposto +. . Poiché il tuo chars è signed, qualsiasi elemento con il valore più alto impostato su 1 viene interpretato come un numero negativo e promosso a un numero intero con lo stesso valore negativo. Ci sono diversi modi per risolvere questo:

  1. cadere la +: ... << test.c[idx] << .... Questo potrebbe stampare il carattere come un carattere piuttosto che un numero, quindi probabilmente non è una buona soluzione.
  2. Declare c come unsigned char. Questo lo promuoverà su un unsigned int.
  3. cast esplicito +test.c[idx] prima che si passi: ... << (unsigned char)(+test.c[idx]) << ...
  4. Impostare i byte superiori del numero intero da zero con binario &: ... << +test.c[idx] & 0xFF << ....Questo mostrerà solo il byte di ordine inferiore indipendentemente da come viene promosso lo char.
+0

char non viene promosso nell'operatore <<, è dovuto all'operatore unario +. Questo può essere facilmente visto se si rilascia + unario dal codice. –

+0

L'eliminazione di unario + operatore stampa il carattere "direttamente", ma sono interessato al loro valore esadecimale reale (l'operatore esadecimale non aiuta altrimenti). Anche il seguente errore: 'test.c [0] == 0xef' – tickferno

+0

Buona chiamata. Modificato di conseguenza. –

Problemi correlati