4 Byte in 1 float wandeln

Gast #3195176
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.
Gast #3195200
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
Gast #3195551
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).
#3195653
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
#3195837
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren