4 Byte in 1 float wandeln

Gast #3195176
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
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?
Gast
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
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?
Gast
> 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).
Gast
> 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.
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
Gast
@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.
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

Eine eigene Frage? Dieser Thread ist über 13 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.