2010-02-10 13 views
5

Je travaille avec HiTech PICC32 sur la série de microprocesseurs PIC32MX, mais je pense que cette question est assez générale pour tous ceux qui savent en C. (C'est presque équivalent à C90, avec sizeof (int) = sizeof (long) = sizeof (float) = 4.)Réassembler le flotteur à partir des octets en ligne

Disons que j'ai lu un mot de données de 4 octets qui représente float. Je peux rapidement le convertir à sa valeur réelle float avec:

#define FLOAT_FROM_WORD(WORD_VALUE) (*((float*) &(WORD_VALUE))) 

Mais cela ne fonctionne que pour les valeurs. Je ne peux pas, par exemple, l'utiliser sur une valeur de retour de la fonction comme:

FLOAT_FROM_WORD(eeprom_read_word(addr)); 

est-il un moyen court et doux de le faire en ligne, à savoir sans appel de fonction ou variable temp? Pour être honnête, il n'y a pas de grande raison pour moi d'éviter un appel de fonction ou un extra var, mais ça m'embête. Il doit y avoir un moyen qui me manque.

Ajouté: Je n'avais pas réalisé que WORD était en fait un typedef commun. J'ai changé le nom de l'argument macro pour éviter toute confusion.

+0

"Mais cela ne fonctionne que pour les valeurs" Vous voulez dire lvalues? Quoi qu'il en soit, avec des optimisations, votre compilateur devrait quand même supprimer l'appel de fonction; il suffit de le coller dans une fonction et regarder l'assemblée pour le savoir. – GManNickG

+0

Chose corrigée [l/r]. Regardera l'assemblée plus tard. – detly

+0

Je vous recommande de mettre ce genre de chose dans une fonction wrapper spécifique à la plate-forme pour garder ce code spécifique à la plate-forme confiné à une petite partie de votre projet. –

Répondre

8

Vous pouvez exécuter le tour dans l'autre sens pour les valeurs retour

float fl; 
*(int*)&fl = eeprom_read_word(addr); 

ou

#define WORD_TO_FLOAT(f) (*(int*)&(f)) 

WORD_TO_FLOAT(fl) = eeprom_read_word(addr); 

ou R Samuel Klatchko suggère

#define ASTYPE(type, val) (*(type*)&(val)) 
ASTYPE(WORD,fl) = eeprom_read_word(addr); 
+3

Si vous voulez généraliser cela plus loin, vous pouvez faire le type pour traiter la variable comme un macro paramètre '#define ASTYPE (var, type) (* (type *) & (var))' et l'utiliser comme 'ASTYPE (fl, WORD) = ... ' –

+0

Bonne suggestion, je vais ajouter cela à la réponse –

+0

Rapide et simple, je l'aime. À votre santé. – detly

0

Pas vraiment une réponse, plus une suggestion. Votre macro FLOAT_FROM_WORD sera plus naturelle à utiliser et plus flexible si elle n'a pas de; à la fin

#define FLOAT_FROM_WORD(w) (*(float*)&(w)) 

fl = FLOAT_FROM_WORD(wd); 
+0

Silly typo, fixe :) – detly

0

Cela peut ne pas être possible dans votre situation exacte, mais la mise à niveau vers un compilateur C99 résoudrait également votre problème. C99 possède des fonctions en ligne qui, tout en agissant comme des fonctions normales dans les paramètres et les valeurs de retour, obtiennent une efficacité améliorée dans exactement ce cas sans aucun des inconvénients des macros.

+0

HiTech ne fait pas un compilateur C99, donc ... ne peut pas faire:/ – detly

1

vous pouvez prendre l'adresse d'une valeur temporaire si vous utilisez une référence const:

FLOAT_FROM_WORD(w) (*(float*)&(const WORD &)(w)) 

mais qui ne fonctionne pas dans c :(

(c ne pas bonnes références? travaille en C++ visuelle)

comme d'autres l'ont dit, que ce soit une fonction inline ou une température dans une définition, le compilateur d'optimiser dehors.

3

Si cela GCC, vous pouvez le faire :

#define atob(original, newtype) \ 
    (((union { typeof(original) i; newtype j })(original)).k) 

Wow. Hideux.Mais l'utilisation est agréable:

int i = 0xdeadbeef; 
float f = atob(i, float); 

Je parie que votre compilateur ne supporte pas non plus l'opérateur typeof ni la union coulée qui ne GCC, puisque ni sont le comportement standard, mais dans tout hasard que votre compilateur peut faire union casting, c'est votre réponse. MODIFIÉ ne pas utiliser typeof:

#define atob(original, origtype newtype) \ 
    (((union { origtype i; newtype j })(original)).k) 

int i = 0xdeadbeef; 
float f = atob(i, int, float); 

Bien sûr, cela ne tient pas compte de la question de ce qui se passe lorsque vous utilisez deux types de tailles différentes, mais est plus proche de « ce que vous voulez », à savoir un simple filtre macro qui retourne une valeur, au lieu de prendre un paramètre supplémentaire. Les paramètres supplémentaires que cette version prend sont juste pour la généralité.

Si votre compilateur ne supporte pas le union casting, ce qui est un tour pur mais non portable, alors il n'y a aucun moyen de le faire comme vous le voulez, et les autres réponses l'ont déjà.

+0

La chose triste est , Microchip fait en fait un compilateur basé sur GCC et ils ont techniquement publié la source. Cependant, je n'ai jamais été capable de l'amadouer pour compiler sur Linux. – detly