Question

I'm working with HiTech PICC32 on the PIC32MX series of microprocessors, but I think this question is general enough for anyone knowledgable in C. (This is almost equivalent to C90, with sizeof(int) = sizeof(long) = sizeof(float) = 4.)

Let's say I read a 4-byte word of data that represents a float. I can quickly convert it to its actual float value with:

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

But this only works for lvalues. I can't, for example, use this on a function return value like:

FLOAT_FROM_WORD(eeprom_read_word(addr));

Is there a short and sweet way to do this inline, i.e. without a function call or temp variable? To be honest, there's no HUGE reason for me to avoid a function call or extra var, but it's bugging me. There must be a way I'm missing.

Added: I didn't realise that WORD was actually a common typedef. I've changed the name of the macro argument to avoid confusion.

Was it helpful?

Solution

You can run the trick the other way for return values

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

or

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

WORD_TO_FLOAT(fl) = eeprom_read_word(addr);

or as R Samuel Klatchko suggests

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

OTHER TIPS

If this were GCC, you could do this:

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

Wow. Hideous. But the usage is nice:

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

I bet your compiler doesn't support either the typeof operator nor the union casting that GCC does, since neither are standard behavior, but in the off-chance that your compiler can do union casting, that is your answer. Modified not to use typeof:

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

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

Of course, this ignores the issue of what happens when you use two types of different sizes, but is closer to "what you want," i.e. a simple macro filter that returns a value, instead of taking an extra parameter. The extra parameters this version takes are just for generality.

If your compiler doesn't support union casting, which is a neat but non-portable trick, then there is no way to do this the "way you want it," and the other answers have already got it.

you can take the address of a temporary value if you use a const reference:

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

but that won't work in c :(

(c doesn't have references right? works in visual c++)

as others have said, be it an inlined function or a temp in a define, the compiler will optimize it out.

Not really an answer, more a suggestion. Your FLOAT_FROM_WORD macro will be more natural to use and more flexible if it doesn't have a ; at the end

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

fl = FLOAT_FROM_WORD(wd);

It may not be possible in your exact situation, but upgrading to a C99 compiler would solve your problem too.

C99 has inline functions which, while acting like normal functions in parameters and return values, get improved efficiency in exactly this case with none of the drawbacks of macros.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top