2010-05-31 33 views
16

Lo ideal sería el siguiente código tomaría un flotador en la representación IEEE 754 y convertirlo en hexadecimalIEEE 754 del flotador a hexadecimal con c - printf

void convert() //gets the float input from user and turns it into hexadecimal 
{ 
    float f; 
    printf("Enter float: "); 
    scanf("%f", &f); 
    printf("hex is %x", f); 
} 

No estoy muy seguro de lo que va mal. Está convirtiendo el número en un número hexadecimal, pero uno muy equivocado.

123.1443 gives 40000000 
43.3  gives 60000000 
8  gives 0 

por lo que está haciendo algo, no estoy muy seguro de qué.

ayuda se agradece

+0

'float' se promueve a' double' en funciones variadas (ver la respuesta de James McNellis). Pruebe 'printf (" hex es% lx ", f);' en su lugar. Para código portátil, observe sizeof (doble) en comparación con sizeof (int) y sizeof (long) para determinar si se debe usar 'x' o' lx'. – tomlogic

+0

¿Cómo sabes que es IEEE 754? –

+0

@tomlogic: para código portable, no pase un valor de coma flotante a 'printf' con un formato que requiera un entero. El comportamiento no está definido, incluso si los tamaños coinciden. (Saludos desde 7 años en el futuro. No preguntar) –

Respuesta

24

Cuando se pasa una float como argumento a una función variadic (como printf()), se promueve a un double, que es dos veces tan grande como una float (por lo menos en la mayoría de las plataformas)

Una forma de evitar esto sería a emitir el float a un unsigned int cuando se pasa como argumento a printf():

printf("hex is %x", *(unsigned int*)&f); 

Esto también es más correcto, ya que printf() utiliza los especificadores de formato para determinar cómo grande cada argumento es

Técnicamente, esta solución infringe el strict aliasing rule. Se puede evitar esto mediante la copia de los bytes de la float en un unsigned int y luego pasa que a printf():

unsigned int ui; 
memcpy(&ui, &f, sizeof (ui)); 

printf("hex is %x", ui); 

Ambas soluciones se basan en la suposición de que sizeof(int) == sizeof(float), que es el caso en muchos de 32 bits sistemas, pero no es necesariamente el caso.

+1

Para evitar la violación de la regla de aliasing estricta, intente * (volatile unsigned int *) (flotación volátil *) (&f); – Joshua

+0

¿Por qué no puede simplemente printf ("hex es% x \ n", (unsigned int) f)? asumiendo que f puede caber en unsigned int. – Nyan

+4

@Nyan: Porque eso no reinterpretará los bits como un valor sin signo, que convertirá el float a un valor sin signo (entonces, 24.12 se convertiría en 24, que no es el resultado deseado). –

12

Cuando se admite, use% a para convertir el punto flotante a un formato hexadecimal estándar. Aquí está el único document que pude encontrar que enumeró la opción% a.

De lo contrario, debe extraer los bits del valor del punto flotante en un tipo entero de tamaño conocido. Si usted sabe, por ejemplo, que tanto flotador y int son de 32 bits, se puede hacer un reparto rápido:

printf("%08X" , *(unsigned int*)&aFloat); 

Si quieres ser menos dependientes de tamaño, puede utilizar una unión:

union { 
    float f; 
//char c[16]; // make this large enough for any floating point value 
    char c[sizeof(float)]; // Edit: changed to this 
} u; 

u.f = aFloat; 
for (i = 0 ; i < sizeof(float) ; ++i) printf("%02X" , u.c[i] & 0x00FF); 

El orden del ciclo dependería de la arquitectura endianness. Este ejemplo es Big Endian.

De cualquier forma, el formato de punto flotante puede no ser portátil para otras arquitecturas. La opción% a está destinada a ser.

+0

+1: No estaba familiarizado con el '% un 'especificador de formato. Ahora me siento tonto :-) –

+0

+1 para saber sobre% a. ¿Por qué '' char [16]' 'y no' 'char [sizeof (float)] ''? –

+0

C99 es otro documento que lo menciona :-) –

1

¿Qué tal esto?

int main(void){ 
    float f = 28834.38282; 
    char *x = (char *)&f; 
    printf("%f = ", f); 

    for(i=0; i<sizeof(float); i++){ 
    printf("%02X ", *x++ & 0x0000FF); 
    } 

    printf("\n"); 
} 
3

HEX flotar

que pasan mucho tiempo tratando de encontrar la manera de convertir una entrada de HEX de una conexión en serie con formato de IEE754 flotador en flotador. Ahora lo tengo. Solo quería compartir en caso de que pudiera ayudar a alguien más.

#include <stdio.h> 
#include <stdlib.h> 
int main(int argc, char *argv[]) 
{ 

    uint16_t tab_reg[64]     //declare input value recieved from serial connection 
    union IntFloat { int32_t i; float f; }; //Declare combined datatype for HEX to FLOAT conversion 
    union IntFloat val;      
    int i; 
    char buff[50];       //Declare buffer for string 

    i=0; 

    //tab_reg[i]=0x508C;     //to test the code without a data stream, 
    //tab_reg[i+1]=0x4369;     //you may uncomment these two lines. 


    printf("Raw1: %X\n",tab_reg[i]);  //Print raw input values for debug 
    printf("Raw2: %X\n",tab_reg[i+1]);  //Print raw input values for debug 

    rs = sprintf(buff,"0X%X%X", tab_reg[i+1], tab_reg[i]); //I need to swap the words, as the response is with the opposite endianness. 
    printf("HEX: %s",buff);     //Show the word-swapped string 
    val.i = atof(buff);      //Convert string to float :-) 
    printf("\nFloat: %f\n", val.f);   //show the value in float 

} 

Salida:

Raw1: 508C 
Raw2: 436A 
HEX: 0X436A508C 
Float: 234.314636 
2

Este enfoque siempre funcionó bastante bien para mí:

union converter{ 
float f_val; 
unsigned int u_val; 
}; 

union converter a; 
a.f_val = 123.1443f; 
printf("my hex value %x \n", a.u_val); 
2

ejemplo Estúpidamente simple:

unsigned char* floatToHex(float val){ 
    unsigned char* hexVals = malloc(sizeof(float)); 
    hexVals[0] = ((unsigned char*)&val)[0]; 
    hexVals[1] = ((unsigned char*)&val)[1]; 
    hexVals[2] = ((unsigned char*)&val)[2]; 
    hexVals[3] = ((unsigned char*)&val)[3]; 
    return hexVals; 
} 

solución Bastante obvio cuando me di cuenta que fuera. Sin enmascaramiento, memcpy u otros trucos necesarios.

En el ejemplo anterior, era para un propósito específico y sabía que las carrozas eran de 32 bits. Una mejor solución si no está seguro del sistema:

unsigned char* floatToHex(float val){ 
    unsigned char* hexVals = malloc(sizeof(float)); 
    for(int i = 0; i < sizeof(float); i++){ 
     hexVals[i] = ((unsigned char*)&val)[i]; 
    } 
    return hexVals; 
} 
0

Lo que finalmente trabajó para mí (enrevesado como parece):

#include <stdio.h> 
int main((int argc, char** argv) 
{ 
    float flt = 1234.56789; 
    FILE *fout; 
    fout = fopen("outFileName.txt","w"); 
    fprintf(fout, "%08x\n", *((unsigned long *)&flt); 
     /* or */ 
    printf("%08x\n", *((unsigned long *)&flt); 
} 
Cuestiones relacionadas