2012-03-14 11 views
11

Ho problemi a convertire un int64_t in un array di caratteri e di nuovo. Non so cosa c'è di sbagliato con il codice qui sotto, ha senso per me. Il codice funziona per a come mostrato, ma non il secondo numero b che rientra chiaramente nell'intervallo di int64_t.Come si converte un numero intero a 64 bit in un array di caratteri e di nuovo?

#include <stdio.h> 
#include <stdint.h> 

void int64ToChar(char mesg[], int64_t num) { 
    for(int i = 0; i < 8; i++) mesg[i] = num >> (8-1-i)*8; 
} 

int64_t charTo64bitNum(char a[]) { 
    int64_t n = 0; 
    n = ((a[0] << 56) & 0xFF00000000000000U) 
    | ((a[1] << 48) & 0x00FF000000000000U) 
    | ((a[2] << 40) & 0x0000FF0000000000U) 
    | ((a[3] << 32) & 0x000000FF00000000U) 
    | ((a[4] << 24) & 0x00000000FF000000U) 
    | ((a[5] << 16) & 0x0000000000FF0000U) 
    | ((a[6] << 8) & 0x000000000000FF00U) 
    | (a[7]  & 0x00000000000000FFU); 
    return n; 
} 

int main(int argc, char *argv[]) { 
    int64_t a = 123456789; 
    char *aStr = new char[8]; 
    int64ToChar(aStr, a); 
    int64_t aNum = charTo64bitNum(aStr); 
    printf("aNum = %lld\n",aNum); 

    int64_t b = 51544720029426255; 
    char *bStr = new char[8]; 
    int64ToChar(bStr, b); 
    int64_t bNum = charTo64bitNum(bStr); 
    printf("bNum = %lld\n",bNum); 
    return 0; 
} 

uscita è

aNum = 123456789 
bNum = 71777215744221775 

Il codice dà anche due avvertimenti che non so come sbarazzarsi di.

warning: integer constant is too large for ‘unsigned long’ type 
warning: left shift count >= width of type 
+3

il secondo avvertimento è la chiave. Gli operandi di '<<' sono promossi a 'int', quindi' a [0] << 56' sarà sempre 0. Prova '((int64_t) a [0])' ecc. Il primo avviso è circa 51544720029426255 , devi dire 51544720029426255LL. –

+0

http://ideone.com/dKIWT – aroth

risposta

7

Questo è piuttosto semplice, il problema è che si stanno spostando i bit in array di caratteri, ma dimensioni a[i] è 4 bye (upcast a int), quindi il tuo turno va oltre la portata. Provare a sostituire questo nel codice:

int64_t charTo64bitNum(char a[]) { 
    int64_t n = 0; 
    n = (((int64_t)a[0] << 56) & 0xFF00000000000000U) 
    | (((int64_t)a[1] << 48) & 0x00FF000000000000U) 
    | (((int64_t)a[2] << 40) & 0x0000FF0000000000U) 
    | (((int64_t)a[3] << 32) & 0x000000FF00000000U) 
    | ((a[4] << 24) & 0x00000000FF000000U) 
    | ((a[5] << 16) & 0x0000000000FF0000U) 
    | ((a[6] << 8) & 0x000000000000FF00U) 
    | (a[7]  & 0x00000000000000FFU); 
    return n; 
} 

In questo modo si lanci il char a un numero a 64 bit prima di fare il turno e non andrete fuori scala. Potrai ottenere risultati corretti:

entity:Dev jack$ ./a.out 
aNum = 123456789 
bNum = 51544720029426255 

Solo una nota a margine, penso che questo dovrebbe funzionare bene anche, a patto che non c'è bisogno di sbirciare all'interno della matrice char:

#include <string.h> 

void int64ToChar(char a[], int64_t n) { 
    memcpy(a, &n, 8); 
} 

int64_t charTo64bitNum(char a[]) { 
    int64_t n = 0; 
    memcpy(&n, a, 8); 
    return n; 
} 
+0

Preferirei l'alternativa, memcpy direttamente alla variabile int64_t, ma non penso che funzionerà, ad esempio: char * szInput = "51544720029426255";/* 17 byte, più di 8 byte */ memcpy (& n, szInput, 8); risulterà in overflow, non credi? Grazie – Zennichimaro

+0

No, perché stai specificando che copi solo 8 byte in ogni caso tramite il terzo parametro. – Jack

+1

oh ya .. ma poi copierà solo i primi 8 byte, cout << n; stamperà: 51544720, giusto? 51544720029426255 deve contenere int64_t poiché il valore massimo che può contenere è 9223372036854775807. – Zennichimaro

0

In charTo64bitNum voi hanno bisogno di gettare il char a 64 bit prima di spostarlo:

(((int64_t)a[0] << 56) & 0xFF00000000000000U) 
1
void int64ToChar(char mesg[], int64_t num) { 
    *(int64_t *)mesg = num; //or *(int64_t *)mesg = htonl(num); 

} 
Problemi correlati