Pregunta

Estoy trabajando con HiTech PICC32 en la serie PIC32MX de los microprocesadores, pero creo que esta pregunta es lo suficientemente general para cualquier entendido en C. (Esto es casi equivalente a C90, con sizeof (int) = sizeof (long) = sizeof (float) = 4).

Digamos que he leído una palabra de 4 bytes de datos que representa una float. Puedo convertir rápidamente a su valor flotante real con:

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

Pero esto sólo funciona para lvalues. No puedo, por ejemplo, utilizar esto en un valor devuelto por una función como:

FLOAT_FROM_WORD(eeprom_read_word(addr));

¿Hay una manera breve y dulce para hacer esto en línea, es decir, sin una llamada de función o variable temp? Para ser honesto, no hay razón enorme para mí para evitar una llamada de función o var extra, pero me está molestando. Tiene que haber una manera de que me falta.

Agregado: no me daba cuenta de que en realidad era un WORD typedef común. He cambiado el nombre del argumento macro para evitar confusiones.

¿Fue útil?

Solución

Puede ejecutar el truco a la inversa para los valores de retorno

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

o

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

WORD_TO_FLOAT(fl) = eeprom_read_word(addr);

o como sugiere R Samuel Klatchko

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

Otros consejos

Si esto fuera GCC, usted puede hacer esto:

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

Wow. Horrible. Pero el uso es agradable:

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

apuesto a que tu compilador no admite el operador de typeof ni el union fundición que hace CCG, ya que ni son el comportamiento estándar, pero en la remota posibilidad de que el compilador puede hacer la colada union, que es su respuesta. Modificado para no utilizar typeof:

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

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

Por supuesto, esto pasa por alto la cuestión de lo que sucede cuando se utiliza dos tipos de diferentes tamaños, pero está más cerca de "lo que quiere", es decir, un filtro de macro simple que devuelve un valor, en lugar de tomar un parámetro adicional. Los parámetros adicionales de esta versión toma son sólo para la generalidad.

Si el compilador no admite la fundición union, que es un buen truco, pero no portátil, entonces no hay manera de hacer esto la "forma que desee", y las otras respuestas ya han conseguido.

se puede tomar la dirección de un valor temporal si se utiliza una referencia constante:

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

pero eso no va a funcionar en c: (

(c no tiene referencias verdad? Obras en Visual C ++)

como han dicho otros, ya sea una función inline o una temperatura en una definición, el compilador optimizará a cabo.

No es realmente una respuesta, más una sugerencia. Su macro FLOAT_FROM_WORD será más natural de usar y más flexible si no tiene; al final

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

fl = FLOAT_FROM_WORD(wd);

Puede que no sea posible en su situación exacta, pero la actualización a un compilador C99 resolvería su problema también.

C99 tiene funciones en línea que, al tiempo que actúa como funciones normales de los parámetros y devolver valores, obtener una mayor eficiencia en este caso exactamente con ninguno de los inconvenientes de las macros.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top