2012-03-14 17 views
11

Int64_t öğesini bir char dizisine dönüştürmede sorun yaşıyorum. Aşağıdaki kodda neyin yanlış olduğunu bilmiyorum, mantıklı bir mantığa sahiptir. Kod, gösterildiği gibi a için çalışır, ancak int64_t aralığının içine düştüğü ikinci sayı olan b'u çalıştırmaz.64 bit tamsayı bir char dizisine ve arkaya nasıl dönüştürebilirim?

#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; 
} 

çıkış kodu da ben kurtulmak için nasıl bilmiyorum iki uyarı verir

aNum = 123456789 
bNum = 71777215744221775 

olduğunu.

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

ikinci uyarı anahtarıdır. "<<" işlenenleri "int" olarak tanıtılır, bu yüzden bir [0] << 56 'her zaman 0 olacaktır. Deneme ((int64_t) a [0]) 'vb. İlk uyarı yaklaşık 51544720029426255 hakkındadır. 51544720029426255LL demek zorundasınız. –

+0

http://ideone.com/dKIWT – aroth

cevap

7

Bu oldukça basit, sorun bir karakter dizisi ancak boyutu bit değiştiriyor olmasıdır a[i] 4 byes (int'a kadar yükseliyor), böylece vardiyanız aralıktan geçer. Kodunuzdaki bu değiştirmeyi deneyin:

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; 
} 

Bu şekilde kayması yapmadan önce 64bit numarasına char döküm ve size aralığında gitmeyecek. Doğru sonuçlar elde edeceğiz:

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

Sadece bir yan not, ben bu char diziye içinde gözetleme gerekmez varsayarak çok iyi çalışır düşünüyorum: charTo64bitNum yılında

#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

Alternatif, memcpy'yi doğrudan int64_t değişkenine tercih ediyorum, ancak çalışacağını sanmıyorum, örneğin: char * szInput = "51544720029426255";/* 17 bayt, 8 bayttan fazla */ memcpy (& n, szInput, 8); taşma ile sonuçlanacak, değil mi? Teşekkürler – Zennichimaro

+0

Hayır, üçüncü parametreyle herhangi bir durumda yalnızca 8 bayt kopyalayacağınızı belirtiyorsunuz. – Jack

+1

oh ya .. ama sonra sadece ilk 8 bayt kopyalayacak, cout << n; yazdıracak: 51544720, değil mi? 51544720029426255, tutabileceği maksimum değer 9223372036854775807 olarak tutulabileceğinden int64_t içinde tutulmalıdır. – Zennichimaro

0

sen bu değişme önce 64 bit'e kömürü döküm gerekir:

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

}