Question

Je travaille avec HiTech PICC32 sur la série PIC32MX de microprocesseurs, mais je pense que cette question est assez générale pour tous ceux qui knowledgable en C. (Ceci est presque équivalent à C90, avec sizeof (int) = sizeof (long) = sizeof (float) = 4).

Disons que je lis un mot de 4 octets de données qui représente un float. Je peux rapidement convertir à sa valeur réelle avec flotteur:

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

Mais cela ne fonctionne que pour lvalues. Je ne peux pas, par exemple, utiliser une valeur de retour de la fonction comme:

FLOAT_FROM_WORD(eeprom_read_word(addr));

Y at-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 aucune raison énorme pour moi d'éviter un appel de fonction ou var supplémentaire, mais il me casser les pieds. Il doit y avoir un moyen que je suis absent.

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

Était-ce utile?

La solution

Vous pouvez exécuter le tour dans l'autre sens pour les valeurs de 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 comme R Samuel Klatchko suggère

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

Autres conseils

Si cela GCC, vous pouvez faire ceci:

#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 la coulée de union, qui 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 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 cette version prend ne sont que pour la généralité.

Si votre compilateur ne prend pas en charge la coulée de union, ce qui est une astuce mais non portable, alors il n'y a pas moyen de faire la « comme vous le voulez », et les autres réponses ont déjà obtenu.

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 cela ne fonctionne pas dans c: (

(c n'a pas de références fonctionne bien? Dans visual c ++)

comme d'autres l'ont déjà dit, que ce soit des fonctions en ligne ou une température dans une définition, le compilateur d'optimiser le.

Pas vraiment une réponse, plus une suggestion. Votre macro FLOAT_FROM_WORD sera plus naturel d'utiliser et plus souple si elle ne possède pas; à la fin

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

fl = FLOAT_FROM_WORD(wd);

Il ne peut pas être possible dans votre situation exacte, mais la mise à niveau d'un compilateur C99 résoudrait aussi votre problème.

C99 a fonctions en ligne qui, tout en agissant comme des fonctions normales dans les paramètres et les valeurs de retour, obtenir une meilleure efficacité dans ce cas exactement avec aucun des inconvénients des macros.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top