Aufbau einer 32-bit-float-out der 4 composite bytes
Ich versuche zu bauen, ein 32-bit-float-out der 4 composite-bytes. Gibt es eine bessere (oder mehr tragbare) Weg, dies zu tun, als mit der folgenden Methode?
#include <iostream>
typedef unsigned char uchar;
float bytesToFloat(uchar b0, uchar b1, uchar b2, uchar b3)
{
float output;
*((uchar*)(&output) + 3) = b0;
*((uchar*)(&output) + 2) = b1;
*((uchar*)(&output) + 1) = b2;
*((uchar*)(&output) + 0) = b3;
return output;
}
int main()
{
std::cout << bytesToFloat(0x3e, 0xaa, 0xaa, 0xab) << std::endl; //1.0 /3.0
std::cout << bytesToFloat(0x7f, 0x7f, 0xff, 0xff) << std::endl; //3.4028234 × 10^38 (max single precision)
return 0;
}
- Wenn man bedenkt, dass dies war meine erste Frage auf Stack Overflow, ich bin begeistert, auf den verschiedenen Antworten. Ich danke allen für Ihren input.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Könnte man eine
memcpy
(Ergebnis)oder eine union* (Ergebnis)
Aber dies ist nicht mehr tragbar als Sie Ihren code, da es keine Garantie dafür, dass die Plattform little-endian-oder die
float
ist mit IEEE binary32 oder sogarsizeof(float) == 4
.(Anmerkung*: Wie bereits erläutert durch @James, ist es technisch nicht erlaubt in der standard-C++ §[Klasse.union]/1) Zugriff auf das union-Mitglied
u.f
.)sizeof(float)
problem, können Sie einfach erklären, dieb
Mitglied alsuchar b[sizeof(float)];
.Folgende Funktionen packen/entpacken bytes zur Darstellung eines single-precision floating-point-Wert zu/von einem Pufferspeicher in network-byte-order. Nur der pack-Methode nehmen muss, endianness zu berücksichtigen, da die unpack-Methode explizit Konstrukte der 32-bit-Wert aus den einzelnen bytes durch bit-shifting Ihnen den entsprechenden Betrag und dann eine logische ODER-Funktion zusammen. Diese Funktionen gelten nur für C/C++ - Implementierungen zu speichern, dass ein Schwimmer in 32-bit. Dies gilt für IEEE 754-1985 Gleitkomma-Implementierungen.
Können Sie
std::copy
:Dies vermeidet die union hack, das ist technisch nicht erlaubt, durch die Sprache. Es vermeidet auch die Häufig verwendete
reinterpret_cast<float*>(byte_array)
, die gegen die strict-aliasing-Regeln (es ist erlaubt, neu zu interpretieren jedes Objekt als ein array vonchar
, so diereinterpret_cast
s in dieser Lösung nicht gegen die strict-aliasing-Regeln).Es basiert immer noch auf
float
vier bytes in der Breite und stützt sich auf Ihre vier bytes werden eine gültige floating point Zahl in Ihrer Umsetzung der floating-point-format, aber Sie haben entweder zu machen, diese Annahmen oder schreiben Sie special-handling-code, um die Konvertierung zu tun.sizeof(float) == 4
und nicht endianness in Betracht. Es verhindert nur, dassreinterpret_cast<float*>(some_uchar_array)
und die union hack.reinterpret_cast<float*>(byte_array)
muss erlaubt sein, wenn die byte_array (1) ordnungsgemäß ausgerichtet ist und (2) enthält tatsächlich ein schweben. Ich denke so, weil es sonst unmöglich wäre, zumemcpy
einefloat
zu einem anderenfloat
(seitmemcpy
schreibt ein byte-array), und noch einfloat
ist die archetypische POD-Typ.memcpy
nicht interpretieren eines byte-array als float; es interpretiert ein schweben als ein byte-array.memcpy
selbst; offensichtlich funktioniert nur auf byte-arrays. Es ist die Garantie, dass Sie können verwenden Sie die output-byte-array als float.Gibt es keine Möglichkeit, das zu tun dieses tragbare, da die verschiedenen Plattformen verwenden können:
Ich Frage mich auch, wo Sie diese 4 bytes aus?
Wenn ich davon ausgehe, dass man Sie aus einem anderen system, und Sie können garantieren, dass beide Systeme verwenden genau die gleiche Methode zum speichern von Gleitkomma-Werten im Speicher, die Verwendung der union-trick. Ansonsten ist dein code ist fast garantiert nicht tragbar.
Wenn Sie möchten, eine portable Möglichkeit, dies zu tun, müssen Sie ein wenig code schreiben zu erkennen, den endian Typ des Systems.
1./3.
ist eindouble
, nicht einfloat
. Sollten Sie etwas verwenden wie1.0f/3
.