Wie man float-bytes?
Ich bin mit dem HIDAPI, um Daten zu senden, um ein USB-Gerät. Diese Daten können nur gesendet werden als byte-array und muss ich senden Sie ein paar float-zahlen in diesem array. Ich weiß, schwimmt 4 bytes, also dachte ich, das könnte funktionieren:
float f = 0.6;
char data[4];
data[0] = (int) f >> 24;
data[1] = (int) f >> 16;
data[2] = (int) f >> 8;
data[3] = (int) f;
Und später alles was ich zu tun hatte, war:
g = (float)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]) );
Aber testen das zeigt mir, dass die Zeilen wie data[0] = (int) f >> 24;
gibt immer 0
. Was ist Los mit meinem code und wie mache ich das richtig (d.h. brechen Sie ein Schwimmer innere Daten in 4 char Byte und Wiederaufbau die gleiche float später)?
EDIT:
War ich in der Lage, dies zu erreichen mit den folgenden codes:
float f = 0.1;
unsigned char *pc;
pc = (unsigned char*)&f;
//0.6 in float
pc[0] = 0x9A;
pc[1] = 0x99;
pc[2] = 0x19;
pc[3] = 0x3F;
std::cout << f << std::endl; //will print 0.6
und
*(unsigned int*)&f = (0x3F << 24) | (0x19 << 16) | (0x99 << 8) | (0x9A << 0);
Ich weiß, memcpy() ist eine "sauberere" Weg, es zu tun, aber auf diese Weise ich denke, die performance ist etwas besser.
(int)f >> 24
zurück 0
ist, dass die int
gegossen f
gleich 0
in den ersten Platz: der cast sendet die Schwimmer auf Ihrem Boden. Es ist Undefiniertes Verhalten, aber es zu tun, hacky, wie Sie brauchen so etwas wie *(int*)&f >> 24
.InformationsquelleAutor mFeinstein | 2014-01-08
Du musst angemeldet sein, um einen Kommentar abzugeben.
Kannst du es so machen:
Damit dies funktioniert, beide Rechner müssen die gleiche floating-point-Darstellungen.
So wurde zu Recht darauf hingewiesen, in den Kommentaren, die Sie nicht unbedingt tun müssen, um die zusätzlichen
memcpy
; statt, können Sie Sie behandelnf
direkt als ein array von Zeichen (jeder Fehler). Sie haben noch zu tunmemcpy
auf der empfangenden Seite, obwohl, da können Sie nicht behandeln eine beliebige Reihe von Zeichen, die als float! Beispiel:Ich mag diese Antwort, aber ich wurde neugierig, es gibt nicht andere Wege für eine byte-Ebene Zugriff auf ein float?
ist eine Konstante vom Typ
float
,0.6
ist eine Konstante vom Typdouble
. Eine Konstante vom Typdouble
umgewandelt werden würde, umfloat
automatisch sowieso (aber naiv-Compiler generieren, schlechter code fürf = 0.6
, und einige Plattformen könnten Runde anders). Es gibt andere Möglichkeiten byte-level-Zugriff, abermemcpy
ist der beste Weg hier.Ja, Sie können behandeln
f
direkt als array von chars:char const * data = (char const *)&f;
jetzt verwendendata[i]
für eine Reihe voni
.Es gibt Orte, wo unterschieden nicht zwischen float, double und int-Konstanten können erhalten Sie in Schwierigkeiten, so ist es keine schlechte Idee, machen Sie eine Gewohnheit, immer die Angabe der
f
oderd
suffix. Having said, die, ich muss zugeben, ich Neige dazu, dies nur tun, wenn ich entweder müssen sicherstellen, dass es die richtige geben, oder müssen sicherstellen, dass der Leser versteht, welche Art es ist.InformationsquelleAutor Kerrek SB
In standard-C ist garantiert, dass jede Art zugegriffen werden kann als ein array von bytes.
Ein gerader Weg, dies zu tun ist, natürlich, durch den Einsatz der Gewerkschaften:
Wie Sie sehen können, ist es nicht notwendig, überhaupt zu verwenden memcpy oder Zeiger...
Den
union
Ansatz ist leicht zu verstehen, standard und schnell.BEARBEITEN.
Ich werde erklären, warum dieser Ansatz ist gültig in C (C99).
CHAR_BIT
bits (eine integer-Konstante >= 8, in fast allen Fällen ist 8).unsigned char
Art nutzt alle seine bits zur Darstellung des Wertes des Objekts, die eine nicht-negative Zahl, in eine rein binäre Darstellung. Dies bedeutet, dass es keine Polsterung bits oder bits verwendet, für alle anderen extrange purpouse. (Das gleiche ist nicht eine Garantie fürsigned char
oderchar
Arten).unsigned char [n]
(z.B. durch memcpy); [...]"Mehr Informationen:
Eine Diskussion in google groups
Typ-Zweideutigkeiten
EDIT 2
Weiteres detail der standard C99:
Ja, mein code ist standard in C99. Ich bin nicht ziemlich sicher, wenn die union Technik ist standard in C89. (Die
int
innerhalb derfor
Schleife ist nur gültig in C99). Allerdings ist die Frage, hat der tagc
aber nichtc++
.Ja, natürlich, es war nur eine Bemerkung. Manchmal denken die Menschen, die Sie anwenden können, die Dinge von einer Sprache in die andere, also ich wollte einfach auf der sicheren Seite. C ist viel entspannter über den Zugriff auf den Speicher als C++ ist; ich habe nicht die standard-Referenz, das sagt diese gültig ist, aber ich vertraue darauf, du hast Recht.
Ich ging in die Typ-Zweideutigkeiten durch die Gewerkschaften Minenfeld in Antwort und ich stehen einige der besseren Diskussionen. Pascal Cuoq interpretation und der DR. er links unterstützt, es wurde legal, da C89. Die C++ - Fall überhaupt nicht klar und ich würde stützen Sie sich auf die Seite, es wird nicht definiert, es darf aber nicht sein.
Ich bezog mich auf Zweck von Gewerkschaften in C und C++, und auch ich verlinkte diese eine Zugriff auf inaktiv union-Mitglied - nicht definiert?.
InformationsquelleAutor pablo1977
Die Sprache C garantiert, dass jeder Wert von jedem type1 zugegriffen werden kann als ein array von bytes. Die Art der bytes ist
unsigned char
. Hier ist ein low-level-Weg zu kopieren ein float in ein array von bytes.sizeof(f)
ist die Anzahl der bytes zum speichern des Wertes der variablef
; Sie können auchsizeof(float)
(Sie können entweder übergebensizeof
eine variable oder ein komplexer Ausdruck, oder seine Art).Funktionen
memcpy
odermemmove
genau das tun (oder eine optimierte version davon).Brauchen Sie nicht einmal zu machen, diese zu kopieren, obwohl. Sie können direkt übergeben wird ein pointer auf die float-zu den write-to-USB-Funktion und sagt ihm, wie viele bytes zu kopieren (
sizeof(f)
). Sie müssen einen expliziten cast, wenn die Funktion nimmt einen Zeiger-argument andere alsvoid*
.Hinweis: dies funktioniert nur, wenn das Gerät verwendet die gleiche Darstellung von floating-point-zahlen, die Häufig, aber nicht universell. Die meisten Maschinen verwenden Sie die IEEE-floating-point-Formate, aber Sie müssen möglicherweise wechseln der endianness.
Als für das, was falsch ist mit Ihrem Versuch: den
>>
Betreiber betreibt auf Ganzzahlen. In dem Ausdruck(int) f >> 24
,f
ist gegossen, um eineint
; wenn Sie geschrieben hattenf >> 24
ohne den cast,f
würde trotzdem automatisch in eineint
. Die Konvertierung einer Gleitkommazahl in eine Ganzzahl kommt es durch abschneiden oder Runden (in der Regel gegen 0, aber die Regel ist von der Plattform abhängig). 0.6 gerundet auf eine ganze Zahl 0 oder 1, sodata[0]
ist 0 oder 1 und die anderen 0.Müssen Sie handeln auf die bytes des float-Objekts, nicht auf den Wert.
1 Ohne Funktionen, die nicht wirklich bearbeitet werden, die in C, aber einschließlich der Funktions-Zeiger, die Funktionen decay automatisch.
for
? mit<<
und|
Aufteilung der bytes?und andere integer-Operationen wird Ihnen nicht helfen, es. Siehe mein edit.
Ja sehe ich, aber ich dachte, casting die Schwimmer auf ein unsigned char-array könnte den trick tun. Ich versuche nur, zu Vermeidung unnötiger code, da dieser läuft in einem interrupt. Aber wenn es anfängt zu erschweren, so memcpy fast die gleiche und ich werde es verwenden.
Sie können nicht werfen, um einen array-Typ, aber das casting einen Zeiger auf float zu einem
unsigned char *
hat im wesentlichen die gleiche Sache.InformationsquelleAutor Gilles
Vorausgesetzt, dass beide Geräte haben die gleiche Vorstellung davon, wie Schwimmern vertreten sind, warum dann nicht einfach eine
memcpy
. ich.eInformationsquelleAutor Ed Heal
ist der sicherste Weg, dies zu tun, wenn Sie die Kontrolle über beide Seiten zu senden, eine Art standardisierte Darstellung... dies ist nicht die effizienteste, aber es ist nicht zu schlecht für kleine zahlen.
konvertiert in float mit library-Funktion
atof
oderatof_l
.natürlich ist das nicht die optimalste, aber es wird sicher einfach sein, zu Debuggen.
wollte man mehr optimiert und kreativ, erstes byte ist Länge anschließend der exponent, dann jedes byte mit 2 Nachkommastellen... also
34.56
wirdchar array[] = {4,-2,34,56};
sowas wäre tragbar... ich würde nur versuchen, nicht zu übergeben Binär float-Darstellungen herum... da kann es schnell chaotisch.InformationsquelleAutor Grady Player
Könnte es sicherer sein, um der union die float und char-array. Setzen Sie in der float-Mitglied ist, ziehen Sie die 4 (oder was auch immer die Länge) bytes.
Bull. Das ist der ganze Zweck einer union... zu setzen im - Daten in einem format, und ziehen Sie aus - die unveränderte bits als ein anderes format.
Nein, das ist nicht der Sinn einer Gewerkschaft ist. Der Zweck der union ist die Verwendung der gleichen Scheibe-Speicher zum speichern verschiedener Daten, wie verschiedenen Zeiten. In C89, das Verhalten wird durch die Implementierung festgelegt. In C++, GCC tut dies nutzen zu optimieren; ich dachte, einige Versionen haben auch dieses in C, aber nach der Suche ist es, ich war falsch: das ist sicher mit GCC. C11 hat sich ebenfalls geändert, um diese definierte, es ist also wohl sicher in der Praxis auf den aktuellen Compiler, auch wenn Sie nicht vollständig C11-konform.
Falsch. Die Erster mit einer union ist es, die bits und bytes in einer bestimmten Menge Daten, auf die zugegriffen werden, die in unterschiedlicher Weise -- als float und als ein array von chars (bytes), zum Beispiel. Es kann verwendet werden, um Platz zu sparen durch die Nutzung der Speicher für andere Zwecke bei anderen mal, aber das ist eine sekundäre Verwendung.
Wieder, Nein, Sie haben es genau rückwärts. Typ Zweideutigkeiten in den Gewerkschaften wurde explizit nicht standard ist (wenn auch sehr unterstützt), die in früheren Versionen des Standards. Der primäre Zweck einer union ist die Speicherung von unterschiedlichen, unabhängigen Objekten, die in denselben Platz im Speicher (oft, aber nicht notwendigerweise, mit einem enum-oder integer-Objekt in der Nähe, der angibt, welches Feld der union ist aktuell gültig).
InformationsquelleAutor Phil Perry