2010-02-10 7 views
5

Estoy trabajando con HiTech PICC32 en la serie de microprocesadores PIC32MX, pero creo que esta pregunta es lo suficientemente general para cualquiera que sepa de C. (Esto es casi equivalente a C90, con sizeof (int) = sizeof (long) = sizeof (float) = 4.)Reensamblar float desde bytes en línea

Digamos que leo una palabra de datos de 4 bytes que representa un float. Puedo convertirlo rápidamente a su valor real de flotación con:

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

Pero esto solo funciona para lvalues. No puedo, por ejemplo, el uso de este en un valor de retorno de la 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 sincero, no hay una ENORME razón para que evite una llamada a función o var adicional, pero me está molestando. Debe haber una forma en la que me estoy perdiendo.

Agregado: No me di cuenta de que WORD era en realidad un typedef común. Cambié el nombre del argumento de macro para evitar confusiones.

+0

"Pero esto solo funciona para los valores" ¿Quiere decir lvalues? De todos modos, con las optimizaciones su compilador debería eliminar la llamada a la función de todos modos; simplemente póngalo en una función y mire la asamblea para descubrirlo. – GManNickG

+0

Lo corregido [l/r]. Veremos el montaje más tarde. – detly

+0

Te recomiendo que pongas este tipo de cosas en una función de contenedor específica de la plataforma para mantener este código específico de la plataforma limitado a una pequeña parte de tu proyecto. –

Respuesta

8

Puede ejecutar el truco otro camino para el regreso valora

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 R Samuel Klatchko sugiere

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

Si quisiera generalizar eso más, podría hacer que el tipo trate la variable como un parámetro macro '#define ASTYPE (var, type) (* (type *) & (var))' y luego úselo como 'ASTYPE (fl, WORD) = ... ' –

+0

Buena sugerencia, voy a agregar que a la respuesta –

+0

Rápido y simple, me gusta. Aclamaciones. – detly

0
No

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 una; al final

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

fl = FLOAT_FROM_WORD(wd); 
+0

error tonto, reparado :) – detly

0

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, aunque actúan como funciones normales en parámetros y valores de retorno, obtienen una eficacia mejorada exactamente en este caso sin ninguno de los inconvenientes de las macros.

+0

HiTech no hace un compilador C99, entonces ... no se puede hacer:/ – detly

1

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 adecuadas? trabaja 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.

3

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 union fundición, esa 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 una valor, en lugar de tomar un parámetro extra. Los parámetros adicionales que toma esta versión son solo generales.

Si su compilador no admite el fundido union, que es un truco ordenado pero no portátil, entonces no hay forma de hacer esto de la "manera que lo desee", y las otras respuestas ya lo tienen.

+0

Lo triste es , Microchip en realidad hace un compilador basado en GCC y han lanzado técnicamente la fuente. Sin embargo, nunca he sido capaz de obligarlo a compilar en Linux. – detly

Cuestiones relacionadas