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.
Nimm memcpy; das ist der einzig standardkonforme Weg für solche Hacks. Alternative ist eine richtige Serialisierung / Deserialisierung des Objekts (hier: float).
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?
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.
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
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?
Ein float kommt da schon raus. Nur halt nicht der, der vorher reingesteckt wurde. ;-)
Ein bisschen cast beim ersten Versuch hätte auch geholfen. Da wurde wahrscheinlich zu früh in float gewandelt.
> 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).
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.
> 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
@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.
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.
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.