Comment convertir ou convertir un float en séquence de bits, telle qu’une longue

Bonjour, je travaille dans un environnement C 16 bits et je souhaite convertir une valeur flottante en séquence de bits telle qu’une valeur entière. Je sais comment y parvenir de multiples façons, l’une avec un syndicat; tel que:

union ConvertFloatToInt { float input; unsigned long output; }; 

cela “convertira” les valeurs flottantes en une valeur longue, en lisant la même zone mémoire, en l’interprétant différemment.

 union ConvertFloatToInt x; x.input = 20.00; 

résultat

 x.output = 0x41A00000; 

D’autres méthodes consistent à annuler les conversions de pointeur …

 float input = 40.00; unsigned long output; void* ptr; ptr = &input; output = *(unsigned long*) ptr; 

résultat

 output = 0x42200000; 

C’est l’idée de ce que j’essaie de faire, cependant, je veux que le compilateur fasse la conversion pour moi, pendant la construction, pas pendant l’exécution.

J’ai besoin d’un pour insérer les données flottantes converties dans une constante (const) unsigned long.

Je pensais essayer de convertir la valeur float en vide, puis le vide en non signé long. Quelque chose comme ceci: (et oui c’est incorrect, vous ne pouvez pas jeter un vide)

 const unsigned long FloatValue = (unsigned long) ((void) ((float) 20.654)); 

Y a-t-il un moyen de faire ça? Je pensais peut-être quelque chose avec des pointeurs vides, mais tous les pointeurs vides que je connais nécessitent une variable, et les variables ne peuvent pas être utilisées dans l’atsortingbution de valeurs const.

modifier

J’utilise un compilateur C90. La question est prévue dans la scope du fichier.

Conclusion

La conclusion était qu’il n’y avait pas de solution réelle à cette question, sauf lorsque l’on travaillait dans le bloc. Pour lesquelles plusieurs réponses ont été données, et je vous remercie tous.

Ma solution

Ce n’est pas une bonne solution, mais cela résout mon problème, mais je ne pense pas que cela aidera beaucoup de gens non plus. J’ai créé un petit programme à des fins de démonstration. Ce n’est pas le code de mon projet ni le compilateur utilisé dans mon projet (avant que quelqu’un dise qu’il ne s’agit pas d’un compilateur C90)

Le compilateur utilisé dans la démonstration: gcc (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3

 typedef union { float myfloat; unsigned long mylong; } custom_type; typedef struct { int a; int b; custom_type typeA; custom_type typeB; } my_struct; const my_struct myobj = { 1,2,3.84F,4 }; int main(void) { printf(":: %f\n", myobj.typeA.myfloat); printf(":: %ul\n", myobj.typeA.mylong); return 0; } 

Sortie

 :: 3.840000 :: 1081459343l 

C’est un peu grossier, mais cela fonctionne dans la scope du fichier (mais génère des avertissements).

Vous pouvez le faire en tapant du doigt dans une union anonyme:

 unsigned int i = ((union { float f; unsigned int i; }){5.0}).i; 

Notez que cet initialiseur n’est pas une expression constante et ne peut donc pas être utilisé à la scope du fichier.

Il est spécifié que la norme doit autoriser le typage via une union:

c11

6.5.2.3 Structure et membres du syndicat

95) Si le membre utilisé pour lire le contenu d’un object d’union n’est pas identique au dernier membre utilisé pour stocker une valeur dans l’object, la partie appropriée de la représentation d’object de la valeur est réinterprétée en tant que représentation d’object dans le nouveau. taper comme décrit au 6.2.6 (un processus parfois appelé ” type punning ”). Cela pourrait être une représentation de piège.

D’un sharepoint vue pratique, bien que vous ne puissiez pas utiliser cette méthode pour initialiser une constante de fichier, vous pouvez écrire une fonction d’initialisation qui charge les valeurs dans des variables de fichier au moment de l’initialisation du programme ou du module.

Vous n’allez pas trouver une méthode portable qui vous permet de calculer les valeurs sous forme d’expression constante à la compilation, car les représentations d’object couvertes par la section 6.2.6 de la norme ne s’appliquent qu’au moment de l’exécution. Sinon, un compilateur croisé serait requirejs pour simuler et non pas simplement paramétrer l’environnement d’exécution de sa cible.


Addendum: ceci est valide C ++, à la condition que le type d’ union soit nommé:

 union u { float f; unsigned int i; }; unsigned int i = u{5.0}.i; 

Donc, si vous êtes prêt à écrire en C / C ++ hybride et à le comstackr avec un compilateur C ++, vous pouvez alors effectuer le transtypage au moment de la compilation.

Vous pouvez utiliser un littéral composé C99:

 const unsigned long FloatValue = *(unsigned long *) &(float) {20.654f}; 

Notez que l’initialiseur n’est pas une expression constante et que FloatValue ne peut être déclaré qu’à la scope du bloc et non à celle du fichier.

Je suppose que ces flottants sont des constantes et que, par conséquent, vous pouvez simplement écrire un petit programme pour le faire comme un exercice ponctuel – générer le résultat tel que requirejs. À partir de ce petit programme, faites un travail de copier / coller dans l’autre code.

Si vous en avez beaucoup, pourquoi ne pas simplement écrire un script pour créer le fichier approprié pour C.

Vous devez savoir quelque chose sur les normes à virgule flottante IEEE. http://en.wikipedia.org/wiki/IEEE_floating-point_standard

obtenir les bits de fractions et obtenir les bits d’exposant et les traiter dans une longue

Vous pouvez atteindre votre objective en définissant une constante de type float, puis une macro:

 const float _FloatValue = 20.654; #define FloatValueL *((unsigned long *) &_FloatValue)