2010-05-31 8 views
16

Idéalement le code suivant prendrait un flotteur dans la représentation IEEE 754 et le convertir en hexadécimalConvertir ieee 754 flotteur ensorceler avec 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); 
} 

Je ne suis pas sûr de ce qui va mal. Il convertit le nombre en un nombre hexadécimal, mais un très mauvais.

123.1443 gives 40000000 
43.3  gives 60000000 
8  gives 0 

donc c'est en train de faire quelque chose, je ne suis pas très sûr de quoi.

aide serait appréciée

+0

«float» est promu à «double» dans les fonctions variadiques (voir la réponse de James McNellis). Essayez 'printf (" hex est% lx ", f);' à la place. Pour le code portable, regardez sizeof (double) par rapport à sizeof (int) et sizeof (long) pour déterminer s'il faut utiliser 'x' ou' lx'. – tomlogic

+0

Comment savez-vous que c'est IEEE 754? –

+0

@tomlogic: Pour le code portable, ne pas passer une valeur à virgule flottante 'printf' avec un format qui nécessite un entier. Le comportement n'est pas défini, même si les tailles correspondent. (Ne pas demander.) –

Répondre

24

Lorsque vous passez un float comme argument à une fonction variadique (comme printf()), il est promu à un double, ce qui est deux fois plus grand que un float (au moins sur la plupart des plates-formes).

Une façon de contourner ce serait de jeter le float à un unsigned int quand il passe comme argument à printf():

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

Ceci est également plus correct, puisque printf() utilise le format spécificateurs pour déterminer comment grand chaque argument est. Techniquement, cette solution enfreint la norme strict aliasing rule. Vous pouvez contourner ce problème en copiant les octets du float dans un unsigned int et passant ensuite que, pour printf():

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

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

Ces deux solutions sont basées sur l'hypothèse que sizeof(int) == sizeof(float), ce qui est le cas sur de nombreux 32 bits systèmes, mais ce n'est pas nécessairement le cas.

+1

Pour éviter d'enfreindre la règle stricte d'aliasing, essayez * (volatil unsigned int *) (volatile float *) (&f); – Joshua

+0

Pourquoi ne pas simplement printf ("hex est% x \ n", (entier non signé) f) ??? en supposant que f peut entrer dans un entier non signé – Nyan

+4

@Nyan: Parce que cela ne réinterprétera pas les bits comme une valeur non signée, cela convertira le flottant en une valeur non signée (donc, 24.12 deviendrait 24, ce qui n'est pas le résultat escompté) –

12

Une fois pris en charge, utilisez% a pour convertir un point flottant en format hexadécimal standard. Voici le seul document que je pourrais trouver qui a énuméré l'option% a.

Sinon, vous devez tirer les bits de la valeur à virgule flottante dans un type entier de taille connue. Si vous le savez, par exemple, que les deux float et int sont 32 bits, vous pouvez faire un casting rapide:

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

Si vous voulez être moins dépendant de la taille, vous pouvez utiliser une union:

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

L'ordre de la boucle dépend de l'endianness de l'architecture. Cet exemple est grand endian. Dans tous les cas, le format à virgule flottante peut ne pas être portable pour d'autres architectures. L'option% a est destinée à être.

+0

+1: Je n'étais pas familier avec le '% Maintenant, je me sens bête :-) –

+0

+1 pour savoir à propos de% a. Pourquoi '' char [16] ''et non' 'char [sizeof (float)]''? –

+0

C99 est un autre document qui le mentionne :-) –

1

Que diriez-vous de ceci:?

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 FLOTTER

Je passe un temps assez long à essayer de comprendre comment convertir une entrée HEX à partir d'une connexion série formatée comme IEE754 flotteur en flottant. Maintenant j'ai compris. Je voulais juste partager au cas où cela pourrait aider quelqu'un d'autre.

#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 

} 

Sortie:

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

Cette approche a toujours travaillé très bien pour moi:

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

exemple triviales:

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

solution assez évidente quand je pensais que ce en dehors. Pas de masquage, de memcpy ou d'autres astuces nécessaires.

Dans l'exemple ci-dessus, c'était dans un but précis et je savais que les flotteurs étaient de 32 bits. Une meilleure solution si vous n'êtes pas sûr du système:

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

Ce qui a finalement fonctionné pour moi (alambiqué comme il semble):

#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); 
} 
Questions connexes