2009-01-30 4 views
6

Что я пытаюсь сделать, это преобразовать двойную строку в шестнадцатеричную, а затем вернуться в двойную.double to hex string & hex string to double

Следующий код преобразует строку double-to-hex.

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

Это похоже на работу, однако я не уверен, как преобразовать результирующую строку обратно в двойную. Просьба пояснить:

+0

Вы пытаетесь напечатать необработанные байты или шестнадцатеричное представление числа? Кроме того, вы заботитесь о переносимости самой строки (а не кода)? – strager

+0

Вы предпочитаете решение, которое переносимо, легко кодировать/читать или быстро? – Sparr

+0

Я предпочитаю решение, которое легко кодировать и читать. Мне нужно это, чтобы передать некоторые аргументы между программами. Быть более конкретным - первая программа порождает другую и передает ей 2 удвоения, закодированных в шестнадцатеричную строку. Стрэгер, что вы подразумеваете под «переносимостью самой строки»? – 2009-01-31 19:39:45

ответ

0

Использование sprintf выполняется медленно, если честно, но вы можете вернуть его с помощью sscanf, делая почти то же самое.

Ну, на самом деле, вам придется скопировать два символа в строку буфера, чтобы декодировать их по отдельности. Моя первая попытка, внизу неверна:

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

Вы видите, что% X декодируется как int, а не как байт. Это может даже работать, в зависимости от проблем с низким или высоким уровнем, но это в основном нарушено. Итак, давайте попробуем обойти это:

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

Устранение синтаксических ошибок и т. Д., Я думаю, это должно сработать.

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

Используется нестандартный модификатор hh. Если вы не хотите использовать это, используйте:

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

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

Почти такая же процедура должна сделать

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

Быстрый & грязный.

Обратите внимание, что это играется с огнем. Во-первых, ваши шестнадцатеричные строки можно использовать только на машинах с одинаковым двойным форматом и с одинаковой консистенцией. Во-вторых, функции преобразования не соответствуют строжайшему правилу псевдонимов.

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

Может быть, не самое эффективное решение, но самый простой код.

+0

выглядит как строг, избивающий меня до этого конкретного подхода, и с более применимой реализацией. – Sparr

0

Вы хотите использовать союз и избежать этой вредной привычки:

обугленного * d2c;

d2c = (char *) & a;

Для простоты печати неплохо, когда вы пытаетесь изменить d2c, а затем используйте, когда вы попадаете в неприятности. (То же самое верно для любых двух переменных или указателей (или массивы), совместно же (теоретического) памяти.

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

Я использую ниже функции, чтобы преобразовать двойной в шестнадцатеричную.

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

прохождение 1.0 & 16.0 к этой функции, наблюдаемые обратные значения: 000000000000FF37 & 0000000000003040 соответственно. Думаю, мы должны получить 1 & 10.

1

Для MFC, конвертировать двойной 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

Я удивлен видеть никто не пришел с стандартное решение, которое является спецификатором формата %a в стандарте 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

Я не работаю с 'long double'. – Jahid

+2

@Jahid Вопрос задан для 'double' и ** not ** для' long double'. Если вы хотите сделать это для 'long double', вам понадобится спецификатор' '% LA ''. Возможно, вы захотите перенести мой ответ сейчас. – Ali