Forum: Compiler & IDEs 4 Byte in 1 float wandeln


von Gäst_5 (Gast)


Lesenswert?

Hallo,

ich grübel schon ewig an folgendem Problem:

ich habe in data[0], data[1], data[2] und data[3]
jeweils ein Byte einer übertragenen float Zahl.

Diese zerstückelte float Zahl möchte ich nun wieder zusammen setzen.

Dazu habe ich mir folgendes gedacht:

int i,j,k,l;
float d;

i = data[0];
j = data[1];
k = data[2];
l = data[3];

d = (l<<24) | (k<<16) | (j<<8) | i;

printf("Value: %f",d);


Leider funktioniert es nicht, bzw es wird eine falsche float Zahl 
angezeigt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Nimm memcpy; das ist der einzig standardkonforme Weg für solche Hacks.

Alternative ist eine richtige Serialisierung / Deserialisierung des 
Objekts (hier: float).

von Peter II (Gast)


Lesenswert?

Gäst_5 schrieb:
> Leider funktioniert es nicht, bzw es wird eine falsche float Zahl
> angezeigt.

kann auch nicht gehen, geht nur bei int.


uint8_t data[4];
float d;

memcpy( &d, data, sizeof( float ) );

woher bekommt du das float, wie kommen denn die 4byte zustande?

von ArthurDent (Gast)


Lesenswert?

Ich wuerde glaube ich eine union verwenden.

von Gäst_5 (Gast)


Lesenswert?

prima, mit memcpy funktioniert es!

1000 Dank!

von Peter II (Gast)


Lesenswert?

ArthurDent schrieb:
> Ich wuerde glaube ich eine union verwenden.

aber dafür sind sie nicht gedacht und das verhalten ist nicht definiert. 
Es muss also nicht gehen.

von Reiner (Gast)


Lesenswert?

Hi

hört sich nach einem Bigendian/Littleendian Problem an.
Vorrausgesetzt, beides sind IEEE floats (was mit einiger Sicherheit
anzunehmen ist, probier einfach mal

int i,j,k,l;
float d;

i = data[3];   // umgekehrte Reihenfolge wie oben!!!
j = data[2];
k = data[1];
l = data[0];

d = (l<<24) | (k<<16) | (j<<8) | i;

printf("Value: %f",d);

Reiner

von Peter II (Gast)


Lesenswert?

Reiner schrieb:
> Hi
>
> hört sich nach einem Bigendian/Littleendian Problem an.
> Vorrausgesetzt, beides sind IEEE floats (was mit einiger Sicherheit
> anzunehmen ist, probier einfach mal

unsinn, wie soll dann aus diese berechung jemals eine floatzahl werden?

von Rolf M. (rmagnus)


Lesenswert?

Ein float kommt da schon raus. Nur halt nicht der, der vorher 
reingesteckt wurde. ;-)

von amateur (Gast)


Lesenswert?

Ein bisschen cast beim ersten Versuch hätte auch geholfen. Da wurde 
wahrscheinlich zu früh in float gewandelt.

von g457 (Gast)


Lesenswert?

> Ein float kommt da schon raus. Nur halt nicht der, der vorher
> reingesteckt wurde. ;-)

mit kreativem Casten (und einem passendem Speicheralignment) geht das 
schon auch so:
1
$ cat main.c
2
#include <stdio.h>
3
#include <inttypes.h>
4
5
int main()
6
{
7
  const unsigned char pData[4] = {219, 15, 73, 64};
8
9
  float dResult;
10
  *(uint32_t*)&dResult = (uint32_t)((pData[3] << 24) | (pData[2] << 16) | (pData[1] << 8) | (pData[0]));
11
12
  printf("Value: %f\n", dResult);
13
14
  return 0;
15
}
16
17
$ rm -f main ; gcc -o main main.c
18
19
$ ./main 
20
Value: 3.141593

..will man aber nicht machen (gcc warnt auch (vollkommen zurecht) sobald 
man die Warnungen nicht unterdrückt und Optimierungen anfordert).

von Peter II (Gast)


Lesenswert?

g457 schrieb:
> mit kreativem Casten (und einem passendem Speicheralignment) geht das
> schon auch so:

es fehlen noch ein paar casts. auf einer 16bit CPU geht es nicht.

von g457 (Gast)


Lesenswert?

> auf einer 16bit CPU geht es nicht.

Macht aber nix, weil 16 Bits keine Anforderung waren. Ergo hab ichs mir 
selbst rausgesucht was ich nehm, und das ist amd64.

von Bernd O. (bitshifter)


Lesenswert?

Gäst_5 schrieb:

> Dazu habe ich mir folgendes gedacht:
>
> int i,j,k,l;
> float d;
>
> [...]
>
> d = (l<<24) | (k<<16) | (j<<8) | i;

> Leider funktioniert es nicht, bzw es wird eine falsche float Zahl
> angezeigt.

Die passende Lösung über memcpy wurde ja schon gepostet, deshalb nur 
für's Verständnis:

Der obige Code erzeugt aus den vier Bytes eine 32-Bit Integerzahl, die 
dann in eine Floatzahl gecastet wird.
Die einzelnen Bits, die in den vier Bytes enthalten sind und für Float 
eine völlig andere Bedeutung haben als für Integer (Exponent, Mantisse 
und Vorzeichen) werden so erst mal nach den Integer-Regeln 
(fehl)interpretiert. Diese fehlinterpretierte Integer-Zahl wird dann 
korrekt nach float konvertiert.

Das vermeidet man dadurch, dass man den Compiler die Zahl erst gar nicht 
interpretieren lässt wie beim Beispiel mit memcopy oder beim Beispiel 
von g457 über Adressoperationen (referenzieren/dereferenzieren).

Gruß,
Bernd

von amateur (Gast)


Lesenswert?

@g457

Ich schätze mal auf das:
(uint32_t)((...)|(...)|(...)|...)
kommt es an.

Es zwingt den Compiler erst die Zahl zusammenzustellen und dann fließen 
zu lassen.
Die vielen Zeiger verwirren nur.

von Heiko J. (heiko_j)


Lesenswert?

Warum nicht viel einfacher ?
float * foo = (float *) &data[0];
float bar = *foo;

ggf. musst Du bei little/big endian die bytes im Array vorher 
umsortieren.

von Rolf M. (rmagnus)


Lesenswert?

amateur schrieb:
> Ich schätze mal auf das:
> (uint32_t)((...)|(...)|(...)|...)
> kommt es an.
>
> Es zwingt den Compiler erst die Zahl zusammenzustellen und dann fließen
> zu lassen.


Nein. Das wird von diesem Teil gemacht:

g457 schrieb:
> *(uint32_t*)&dResult

von Bernd O. (bitshifter)


Lesenswert?

amateur schrieb:
> @g457
>
> Ich schätze mal auf das:
> (uint32_t)((...)|(...)|(...)|...)
> kommt es an.
>
> Es zwingt den Compiler erst die Zahl zusammenzustellen und dann fließen
> zu lassen.
Nein - es kommt darauf an zu verhindern, dass der Compiler das Konstrukt 
aus den vier Bytes als Integert interpretiert und dann zwangsweise 
falsch nach float konvertiert.

> Die vielen Zeiger verwirren nur.
Das stimmt - insbesondere Anfänger tun sich damit schwer. Nötig sind sie 
aber trotzdem wenn man nicht über memcpy() gehen will.

Gruß,
Bernd

von ovonel (Gast)


Lesenswert?

was ist das Problem an memcpy() ??

von Ralf G. (ralg)


Lesenswert?

ovonel schrieb:
> was ist das Problem an memcpy() ??

Zu einfach!

von Bernd O. (bitshifter)


Lesenswert?

ovonel schrieb:
> was ist das Problem an memcpy() ??

Vermutlich ist es eine Mischung aus "not invented here" und "was der 
Bauer nicht kennt, frisst er nicht".

;-)

Gruß,
Bernd

von Ralf G. (ralg)


Lesenswert?

ovonel schrieb:
> was ist das Problem an memcpy() ??

Und: viel zu kompatibel.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.