2009-01-30 10 views
6

Co próbuję zrobić, to przekonwertować ciąg podwójny na szesnastkowy, a następnie z powrotem do podwójnego.podwójny łańcuch szesnastkowy i łańcuch szesnastkowy podwójny

Poniższy kod przekształca łańcuch podwójny na szesnastkowy.

char * double2HexString(double a) 
{ 
    char *buf = new char[17]; // double is 8-byte long, so we have 2*8 + terminating \0 
    char *d2c; 
    d2c = (char *) &a; 
    char *n = buf; 
    int i; 
    for(i = 0; i < 8; i++) 
    { 
     sprintf(n, "%02X", *d2c++); 
     n += 2; 
    } 
    *(n) = '\0'; 
} 

Wydaje się, że to działa, jednak nie jestem pewien, jak przekonwertować wynikowy ciąg z powrotem na podwójne. Proszę o poradę :)

+0

Czy próbujesz wydrukować surowe bajty, czy szesnastkową reprezentację liczby? Czy zależy ci na przenośności samego napisu (a nie kodu)? – strager

+0

Wolisz rozwiązanie przenośne, łatwe do kodowania/czytania lub szybkie? – Sparr

+0

Preferuję rozwiązanie, które jest łatwe do kodowania i czytania. Potrzebuję tego, aby przekazać kilka argumentów między programami. Bardziej szczegółowy - pierwszy program spawnuje inny i przechodzi do niego 2 podwójne zakodowane w ciąg szesnastkowy. Strager, co masz na myśli mówiąc o "przenośności samego napisu"? –

Odpowiedz

0

Użycie sprintf jest powolne, szczerze mówiąc, ale możesz to zmienić za pomocą sscanf, robiąc prawie dokładnie to samo.

Cóż, właściwie trzeba by skopiować dwa znaki do ciągu bufora, aby każdy z nich był dekodowany. Moja pierwsza próba, poniżej jest niepoprawna:

double hexString2Double(char *buf) 
{ 
    char *buf2 = new char[3]; 
    double a; 
    char* c2d; 
    c2d = (char *) &a; 
    int i; 

    buf2[2] = '\0' 

    for(i = 0; i < 16; i++) 
    { 
    buf2[0] = *buf++; 
    buf2[1] = *buf++; 
    sscanf(buf2, "%X", c2d++); 
    } 

    return a; 
} 

Widzisz% X jest dekodowany jako int, nie jako bajt. Może nawet zadziałać, w zależności od problemów o niskim końcu/high-endian, ale w zasadzie jest zepsuty. Więc spróbujmy obejść to:

double hexString2Double(char *buf) 
{ 
    char *buf2 = new char[3]; 
    double a; 
    char* c2d; 
    c2d = (char *) &a; 
    int i; 
    int decoder; 

    buf2[2] = '\0' 

    for(i = 0; i < 16; i++) 
    { 
    buf2[0] = *buf++; 
    buf2[1] = *buf++; 
    sscanf(buf2, "%X", &decoder); 
    c2d++ = (char) decoder; 
    } 

    return a; 
} 

Błędy składniowe barring i takie, myślę, że to powinno działać.

1
char *doubleToRawString(double x) { 
    const size_t bytesInDouble = 8; 

    union { 
     double value; 
     unsigned char bytes[bytesInDouble]; 
    } u; 

    u.value = x; 

    char *buffer = new char[bytesInDouble * 2 + 1]; 
    unsigned char *input = u.bytes; 
    char *output = buffer; 

    for(int i = 0; i < bytesInDouble; ++i) { 
     sprintf(output, "%02hhX", *input); 

     ++input; 
     output += 2; 
    } 

    return buffer; 
} 

double rawStringToDouble(const char *input) { 
    const size_t bytesInDouble = 8; 

    union { 
     double value; 
     unsigned char bytes[bytesInDouble]; 
    } u; 

    unsigned char *output = u.bytes; 

    for(int i = 0; i < bytesInDouble; ++i) { 
     sscanf(input, "%02hhX", output); 

     input += 2; 
     ++output; 
    } 

    return u.value; 
} 

używa niestandardowego hh modyfikatora. Jeśli nie chcesz korzystać z tego, użyj:

unsigned int tmp = *input; 
sprintf(output, "%02X", tmp); 

unsigned int tmp; 
sscanf(input, "%02X", &tmp); 
*output = tmp; 
0

Prawie taka sama procedura powinna zrobić

void hex2double(const char* buf, double& a) 
{ 
    char tmpbuf[3]={0}; 
    char *d2c; 
    unsigned int tmp; 
    d2c = (char *) &a; 
    char *n = buf; 
    int i; 
    for(i = 0; i < 8; i++) 
    { 
     tmpbuf[0]=*buf++; 
     tmpbuf[1]=*buf++; 
     sscanf(tmpbuf, "%X", &tmp); 
     *d2c++=tmp; 
    } 
} 

Szybkie & brudne.

Należy jednak pamiętać, że gra z ogniem. Po pierwsze, twoje ciągi heksadecymalne są użyteczne tylko na maszynach o tym samym podwójnym formacie i tej samej endianness. Po drugie, funkcje konwersji nie zawierają reguły ścisłego aliasingu.

3
char *doubleToRawString(double x) { 
    // Assumes sizeof(long long) == 8. 

    char *buffer = new char[32]; 
    sprintf(buffer, "%llx", *(unsigned long long *)&x); // Evil! 
    return buffer; 
} 

double rawStringToDouble(const char *s) { 
    // Assumes sizeof(long long) == 8. 

    double ret; 
    sscanf(s, "%llx", (unsigned long long *)&ret); // Evil! 
    return ret; 
} 
0
#include <stdio.h> 
main() { 
    union double_ull_t { 
    double d; 
    unsigned long long u; 
    } x; 
    scanf("%lf",&x.d); 
    printf("%016llX %lf\n",x.u,x.d); 
    scanf("%016llX",&x.u); 
    printf("%016llX %lf\n",x.u,x.d); 
} 

Może nie jest to najbardziej efektywne rozwiązanie, ale najłatwiej kodu.

+0

wygląda jak strager pokonał mnie w tym konkretnym podejściu, a przy większej implementacji – Sparr

0

Chcesz skorzystać z unii i uniknąć tego zły nawyk:

char * D2C;

d2c = (znak *) & a;

Do samego drukowania nie jest źle, jego przy próbie modyfikacji d2c, a następnie użyciu jest, gdy masz kłopoty. (To samo dotyczy dwóch dowolnych zmiennych lub wskazówek (lub macierzach) dzielenie tej samej (teoretycznej) pamięci.

union 
{ 
    double f; 
    unsigned long ul; 
} myun; 

myun.f = a; 
printf("0x%lX",myun.ul); 

to go the other way (scanf is also a very dangerous function that should be avoided). 

myun.ul=strtoul(string,NULL,16); 
a=myun.f; 
0

Używam funkcji poniżej, aby przekonwertować dwukrotnie do szesnastkowym.

char * double2HexString(double a) 
{ 
    char *buf = new char[17]; // double is 8-byte long, so we have 2*8 + terminating \0 
    char *d2c; 
    d2c = (char *) &a; 
    char *n = buf; 
    int i; 
    for(i = 0; i < 8; i++) 
    { 
     sprintf(n, "%02X", *d2c++); 
     n += 2; 
    } 
    *(n) = '\0'; 
} 

mijania 1.0 & 16.0 do tej funkcji, zwracane wartości są odpowiednio 000000000000FF37 & 0000000000003040. Myślę, że powinniśmy uzyskać 1 & 10.

1

Dla MFC, konwertowanie podwójne do CString :)

CString MFCClass::DoubleToCString(double d, int beforKomma) 
{ 
    char a[17]="ABCDEF"; 
    CString str = _T(""); 
    double dInt=0,dPunkt=0; 
    bool is_otr=0; 
    if (d<0) {is_otr=1; d=-d;} 
    dPunkt = modf(d, &dInt); 
    //целая часть 
    long ld = (long)dInt; 
    long mask = 0xf; 
    int it; 
    while(ld>0) 
    { 
     it = ld&mask; 
     ld = ld>>4; 
     str.Insert(0,a[it]); 
    }; 
    // дробная часть 
    //если целая часть 0: 
    if (str.GetLength()==0) str += _T("0"); 
    str += _T("."); 
    for (int i=0; i<beforKomma; i++) 
    { 
     dPunkt*=16; 
     dPunkt = modf(dPunkt, &dInt); 
     str += a[(int)dInt]; 
    } 

    if (is_otr) str.Insert(0,_T("-")); 
    return (str); 
} 

-345,86783907228863 -> "-159.DE2" (beforKomma = 3)

9

Jestem zaskoczony nikt nie ma pochodzić z standardowe rozwiązanie, które jest specyfikatorem formatu %a w standardzie ISO C99.

#include <iostream> 
#include <string> 
#include <stdio.h> 

std::string double2hexastr(double d) { 

    char buffer[25] = { 0 }; 

    ::snprintf(buffer, 25, "%A", d); // TODO Check for errors 

    return buffer; 
} 

double hexastr2double(const std::string& s) { 

    double d = 0.0; 

    ::sscanf(s.c_str(), "%lA", &d); // TODO Check for errors 

    return d; 
} 


int main() { 

    std::cout << "0.1 in hexadecimal: " << double2hexastr(0.1) << std::endl; 

    std::cout << "Reading back 0X1.999999999999AP-4, it is "; 

    std::cout << hexastr2double("0X1.999999999999AP-4") << std::endl; 

} 
+0

nie działam na "długim podwójnym". – Jahid

+2

@Jahid Pytanie zadawane dla 'double' i ** not ** dla' long double'. Jeśli chcesz zrobić to dla 'long double', potrzebujesz specyfikatora konwersji"% LA "'. Możesz teraz odnieść się do mojej odpowiedzi. – Ali