2009-01-30 17 views
6

Lo que estoy tratando de hacer es convertir una cadena doble a una cadena hexagonal y luego volver al doble.cadena doble a hexagonal y cadena hexagonal a doble

El siguiente código hace una conversión de cadena doble a hexadecimal.

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

Esto parece trabajo, sin embargo, no estoy seguro de cómo convertir la cadena resultante de nuevo a duplicar. Aconsejar :)

+0

¿Está tratando de imprimir los bytes sin formato, o la representación hexadecimal del número? Además, ¿le importa la portabilidad de la cadena en sí (no el código)? – strager

+0

¿Prefiere una solución que sea portátil, fácil de codificar/leer o rápida? – Sparr

+0

Prefiero la solución que es fácil de codificar y leer. Necesito que esto pase algunas discusiones entre programas. Siendo más específico: el primer programa genera otro y le transfiere 2 dobles codificados en una cadena hexadecimal. Strager, ¿qué quiere decir con "portabilidad de la cadena en sí"? –

Respuesta

0

Usar sprintf es lento, para ser honesto, pero puede revertirlo con sscanf, haciendo casi exactamente lo mismo.

Bueno, en realidad, tendría que copiar cada dos caracteres en una cadena de búfer, para decodificar cada uno individualmente. Mi primer intento, a continuación es incorrecto:

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

Ves,% X se decodifica como un int, no como un byte. Incluso podría funcionar, dependiendo de los problemas de baja final/alta calidad, pero básicamente está roto. Por lo tanto, vamos a tratar de conseguir alrededor de eso:

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

Bloqueo de llamadas errores de sintaxis y tal, creo que esto debería funcionar.

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

Esto utiliza el modificador no estándar hh. Si no desea utilizar de eso, utilice:

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

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

Casi el mismo procedimiento debe hacer

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

rápida & sucio.

Tenga en cuenta, sin embargo, que esto está jugando con fuego. En primer lugar, sus cadenas hexadecimales solo se pueden usar en máquinas con el mismo formato doble y el mismo endianness. En segundo lugar, las funciones de conversión son cortas en la regla de aliasing estricta.

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

Quizás no sea la solución más eficiente, pero la más fácil de codificar.

+0

parece que Strager me ganó a este enfoque particular, y con la implementación más aplicable – Sparr

0

que desea utilizar una unión y evitar este mal hábito:

char * d2c;

d2c = (char *) & a;

Para simplemente imprimir no está mal, es cuando intentas modificar d2c y luego usas a es cuando te metes en problemas. (Mismo es cierto para cualquier par de variables o punteros (o matrices) compartiendo la misma memoria (teórico).

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

estoy usando la función a continuación, para convertir doble a hexadecimal.

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

paso 1.0 & 16.0 a esta función, los valores de retorno observados son 000000000000FF37 & 0000000000003040 respectivamente. Creo que deberíamos obtener 1 & 10.

1

Para MFC, convertir a doble 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

me sorprende ver que nadie ha llegado con la solución estándar, que es el especificador de formato %a en el estándar 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

I no funciona para 'long double'. – Jahid

+2

@Jahid La pregunta hecha para 'double' y ** not ** para' long double'. Si desea hacerlo por 'double double', necesita el especificador de conversión' "% LA" '. Es posible que desee votar mi respuesta ahora. – Ali

Cuestiones relacionadas