Sonntag, Dezember 15, 2019

Wie man float in Byte?

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 das Daten-array. Ich weiß, schwimmt haben 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. das brechen eines float innere Daten in 4 char bytes und die Neuerstellung der gleichen float später)?


BEARBEITEN:

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 ein „sauberer“ Weg, es zu tun, aber auf diese Weise ich denke, die performance ist etwas besser.

  • Der Grund (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, dass hacky so, als würden Sie etwas brauchen, wie *(int*)&f >> 24.
InformationsquelleAutor mFeinstein | 2014-01-08

6 Kommentare

  1. 19

    Kannst du es so machen:

    char data[sizeof(float)];
    
    
    float f = 0.6f;
    
    memcpy(data, &f, sizeof f);    //send data
    
    
    float g;
    
    memcpy(&g, data, sizeof g);    //receive data

    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 behandeln f direkt als ein array von Zeichen (jeder Fehler). Sie haben noch zu tun memcpy auf der empfangenden Seite, obwohl, da können Sie nicht behandeln eine beliebige Reihe von Zeichen, die als float! Beispiel:

    unsigned char const * const p = (unsigned char const *)&f;
    for (size_t i = 0; i != sizeof f; ++i)
    {
        printf("Byte %zu is %02X\n", i, p[i]);
        send_over_network(p[i]);
    }
    • dumme Frage, warum das “ f “ nach der 0.6? Ich habe es vorher gesehen, nur nie den Grund…
    • 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 Typ double. Eine Konstante vom Typ double umgewandelt werden würde, um float automatisch sowieso (aber naiv-Compiler generieren, schlechter code für f = 0.6, und einige Plattformen könnten Runde anders). Es gibt andere Möglichkeiten byte-level-Zugriff, aber memcpy ist der beste Weg hier.
    • Ja, Sie können behandeln f direkt als array von chars: char const * data = (char const *)&f; jetzt verwenden data[i] für eine Reihe von i.
    • 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 oder d 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.
    • Das ist ein float literal. Ich dachte, das ist das, was erforderlich ist, also das ist, was ich gebe.
    • Check meine Antwort, um zu sehen, wie den Zugriff auf die einzelnen bytes in einen float.

  2. 8

    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:

     #include <stdio.h> 
    
     int main(void)
     {
        float x = 0x1.0p-3; /* 2^(-3) in hexa */
    
        union float_bytes {
           float val;
           unsigned char bytes[sizeof(float)];
        } data;
    
        data.val = x;
        for (int i = 0; i < sizeof(float); i++) 
              printf("Byte %d: %.2x\n", i, data.bytes[i]);
    
        data.val *= 2;   /* Doing something with the float value */
        x = data.val;    /* Retrieving the float value           */
        printf("%.4f\n", data.val);
    
        getchar();
     }

    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).

    • [5.2.4.2.1(1)] Ein byte hat CHAR_BIT bits (eine integer-Konstante >= 8, in fast allen Fällen ist 8).
    • [6.2.6.1(3)] Die 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ür signed char oder char Arten).
    • [6.2.6.1(2)] Jeden nicht-Bitfeld-Typ ist vertreten in Erinnerung als eine zusammenhängende Folge von bytes.
    • [6.2.6.1(4)] (Zitiert) „gespeicherten Werte in nicht-bit-field-Objekte von einem anderen Objekt-Typ besteht aus n × CHAR_BIT bits, wobei n die Größe eines Objekts dieses Typs in bytes. Der Wert kann kopiert werden in ein Objekt vom Typ unsigned char [n] (z.B. durch memcpy); […]“
    • [6.7.2.1(14)] Einen Zeiger auf ein Struktur-Objekt (insbesondere Gewerkschaften), entsprechend umgewandelt, Punkte zu seinem ersten Mitglied. (Es gibt also keine padding-bytes am Anfang einer union).
    • [6.5(7)] Der Inhalt eines Objekts kann zugegriffen werden, indem ein Charakter-Typ:

    Objekt hat seinen gespeicherten Wert zugegriffen nur von einem lvalue-Ausdruck, der einen von
    die folgenden Arten:

    — Typ kompatibel mit die effektivste Art des Objekts,

    — eine qualifizierte version von einem Typ kompatibel mit die effektivste Art des Objekts,

    — einen Typ, der Sie signiert oder unsigniert-Typ entsprechend der tatsächlichen Art der
    Objekt

    — einen Typ, der Sie signiert oder unsigniert-Typ entsprechend qualifizierte version des
    eine effektive Art des Objekts,

    — ein Aggregat oder union-Typ, einschließlich einer der vorgenannten Arten unter seinen
    Mitglieder (einschließlich, rekursiv,amember der subaggregate oder die union), oder

    ein Zeichen geben

    Mehr Informationen:

    Eine Diskussion in google groups

    Typ-Zweideutigkeiten

    EDIT 2

    Weiteres detail der standard C99:

    • [6.5.2.3(3) Fußnote 82] Typ-Zweideutigkeiten ist erlaubt:

    Wenn das Mitglied verwendet, um Zugriff auf die Inhalte einer union-Objekt ist nicht das gleiche wie das Mitglied zuletzt
    speichern Sie einen Wert in das Objekt, den entsprechenden Teil des Objekts, Darstellung der Wert wird neu interpretiert
    als Objekt-Darstellung in den neuen Typ, wie beschrieben in 6.2.6 (ein Prozess, der manchmal auch als „Typ
    Zweideutigkeiten“). Dies könnte eine Falle sein Darstellung.

    • Ich möchte zu beachten, dass während dies kann gültig in C (C99, denke ich, aber nicht C89?), dies wäre Undefiniertes Verhalten in C++. Nur für den Fall beliebiger C++ – Benutzer zu Fuß durch und sehen Sie dieser.
    • Ja, mein code ist standard in C99. Ich bin nicht ziemlich sicher, wenn die union Technik ist standard in C89. (Die int innerhalb der for Schleife ist nur gültig in C99). Allerdings ist die Frage, hat der tag c aber nicht c++.
    • 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 sagt, dass diese gültig ist, aber ich vertraue darauf, du hast Recht.
    • Beachten Sie, dass ich bin aliasing der float Objekt mit unsigned char[]. Dies ist sehr spezifisch, und ich denke, es ist standard in C++ auch. Ein Undefiniertes Verhalten aufweist, indem eine andere Art, die unsigned char. siehe diese Diskussion
    • Ich ging in die Typ-Zweideutigkeiten durch die Gewerkschaften Minenfeld in die Antwort und ich stehen einige der besseren Diskussionen auf dieser. Pascal Cuoq interpretation und der DR. er links unterstützt, dass es 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.
    • Könnten Sie einen link hinzufügen möchten, um den Entwurf der C99-standard, Sie können finden a Tonne of standards-Entwürfe here.
    • Das ist ein interessanter hack…aber ich bin besorgt über das verschieben der code in C++ in die Zukunft…
    • In C++ haben Sie die Regel, die nur erlaubt, den Zugriff auf die aktiven Gewerkschaftsmitglieder, obwohl, was ich denke, ist nicht sehr unklar. Auf der anderen Seite, dem Absatz, den Sie verknüpft in Ihrer Antwort bezieht sich auf etwas anderes ich glaube, nicht zu Sie, ob es OK ist, um den Zugriff auf die verschiedenen union-Mitglieder auf einmal.
    • Ich bezog mich auf Zweck von Gewerkschaften in C und C++, und auch ich verlinkte diese eine Zugriff auf inaktiv union-Mitglied – nicht definiert?.
    • Danke! Fehlerbericht und späteren Update wirklich verdeutlicht, dass es schon immer gewesen soll gestattet werden, in C. Sehr gut zu wissen.
    • In C89 dies ist ausdrücklich durch die Implementierung festgelegt (C90 §6.3.2.3 Anmerkung 33). Es scheint, dass alle Versionen von GCC (C-compiler) implementieren, C11-konform Verhalten auf dieser Hinsicht.
    • Ich habe Hinzugefügt, weitere details zu meiner Antwort. Es ist eine explizite Erwähnung von Typ-Zweideutigkeiten in C99 (Fußnote 82).
    • Über meine Antwort, denke ich, dass die Technik union+unsigned char [] ist nützlich, um das „Lesen“ der bytes, die ein Objekt, aber wohl die Absicht, „write-back“, die bytes in das array, um die „Wiederherstellung“ des ursprünglichen Objekts ist nicht legal (es wäre Undefiniertes Verhalten). Ich bin kein Experte in C++. Aber ich denke, dass der „Geist“ von C++ zu halten, sich als ein sehr high-level-Sprache, so sollten Sie es vermeiden, „low-level hacks“. Wahrscheinlich müssen Sie tun mehr Forschung über die float Darstellung in C.
    • Ich erinnere mich in der Schule machen einige memory-dumps mit ints und floats und die Werte ändern, um das Verhalten, aber ich denke, es ist eine lange Zeit, so dass ich vergaß, wie es war getan lol…nicht das ich denke, es war ein unsigned char, was genau wie Sie Jungs zeigten
    • In der Praxis ist es fast sicher, dass Typ-Zweideutigkeiten bringt zwar kein problem. Aber Sie können nicht sicher sein, über alles. Können Sie sicher sein, dass dein Programm niemals in ein system mit nicht-padding-bits (für integer-Typen), 2 ergänzen und little endian Typ? Wenn Ihre Antwort „Nein“ oder „weiß nicht“ wissen, dann müssen Sie unsigned char, denn es ist die einzige Art, die in C mit der exakten binären Darstellung garantiert durch die Norm. Nun, wenn Sie schreiben, ein Mitglied einer union, können Sie sicher sein, was passiert, wenn Sie Lesen, ein anderes Mitglied es? (Fast) nur arrays aus char. Typen sind garantiert zu arbeiten.
    • Können Sie sicher sein, dass float immer 4 Byte, little-endian-Format und das format binary32 wie detaillierte durch den standard IEEE 754? Wenn Ihre Antwort „Nein“ oder „weiß nicht“, dann binden Sie die standard-und, besser noch, zu untersuchen, wie sich die float-Typen vertreten sind die beiden Geräte, die Sie verbinden. Dies hängt von mehreren Faktoren ab. Lesen Sie die compiler-Dokumentation für weitere Informationen oder auch überprüfen Sie den Wert der Konstanten, die in <float.h>. Es wäre auch eine gute Idee, um zu studieren floating-point-Formate. IEEE 754
    • Ich glaube, es entspricht den stardads, aber in jedem Fall, ich mache einige test-Routinen, um zu sehen, wenn die Werte gesendet werden wie erwartet

  3. 1

    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 variable f; Sie können auch sizeof(float) (Sie können entweder übergeben sizeof eine variable oder ein komplexer Ausdruck, oder seine Art).

    float f = 0.6;
    unsigned char data[sizeof(float)];
    size_t i;
    for (i = 0; i < sizeof(float); i++) {
        data[i] = (unsigned char*)f + i;
    }

    Funktionen memcpy oder memmove genau das tun (oder eine optimierte version davon).

    float f = 0.6;
    unsigned char data[sizeof(float)];
    memcpy(data, f, sizeof(f));

    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 als void*.

    int write_to_usb(unsigned char *ptr, size_t size);
    result = write_to_usb((unsigned char*)f, sizeof(f))

    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 eine int; wenn Sie geschrieben hatten f >> 24 ohne den cast, f würde trotzdem automatisch in eine int. 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, so data[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.

    • Ist es möglich in einer Zeile, ohne die 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.
  4. 0

    Vorausgesetzt, dass beide Geräte haben die gleiche Vorstellung davon, wie Schwimmern vertreten sind, warum dann nicht einfach eine memcpy. ich.e

    unsigned char payload[4];
    memcpy(payload, &f, 4);
    • Da die bytes gelesen werden, wieder in einen mikrocontroller, und ich war nicht sicher, es war ein memcpy in die mikrocontroller-librabry….aber jetzt sehe ich es ist
  5. 0

    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.

    hostPort writes char * "34.56
    hostPort writes char * "34.56\0" byte by byte
    client reads char * "34.56\0" 
    "
    byte by byte client reads char * "34.56
    hostPort writes char * "34.56\0" byte by byte
    client reads char * "34.56\0" 
    "

    konvertiert in float mit library-Funktion atof oder atof_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 wird char 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.

    • Das wird viel zu umständlich für meine Bedürfnisse, da ich mit einem microcontroller um die Daten zu empfangen und die Leistung ist nicht die beste, um
  6. -2

    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.

    • Eigentlich nicht, zu missbrauchen, eine union dieser Art ist das sicher nicht. Wenn Sie schreiben, um Mitglied einer Gewerkschaft, Sie sind nicht erlaubt zu Lesen, wieder von einem anderen Mitglied (es ist Undefiniertes Verhalten). Compiler nutzen Sie diese Einschränkung zu optimieren.
    • 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).
    • Bestehen Sie nicht mit dieser Idee. Gilles ist richtig. Was ist, wenn Sie eine Typ-Zweideutigkeiten mit einem signed long mit padding-bits, zum Beispiel? Nur unsigned char ist garantiert kompatibel zu sein mit der Absicht, „abrufen“ werden die bits eines Objekts. Aber „kompatibel“ bedeutet nicht „zugänglich“. Um sicherzustellen, dass die bytes „erreichbar“ mit einem anderen Mitglied, wir brauchen eine weitere Forderung der Norm. Ich denke, man kann „gelesen“ werden bytes, aber vielleicht „writing back“ – bytes ist UB. Überprüfen Sie meine Antwort für weitere details.
    • Die Fußnote in der Antwort stackoverflow.com/questions/11373203/…, dass Sie einen link zu gab es schon im C99TC3. Wenn Sie glauben, in standard committee Unfehlbarkeit bedeutet dies, dass es in dem C99-standard alle zusammen, obwohl nicht explizit ausgedrückt. Gemäß dieser interpretation, nichts von C89, C99 und C11 machen es undefiniert zu verwenden, eine union für Typ-Zweideutigkeiten.

Kostenlose Online-Tests

Letzte Fragen

Tun ItemView löst Blase?

Ich habe eine CompositeView für eine Tabelle. Ich habe Trigger-set in der Kind-ItemView für jede Zeile... var TableRow = Marionette.ItemView.extend({ tagName:...

Wie kann ich untersuchen, WCF was 400 bad request über GET?

Die folgenden WCF-endpoint funktioniert gut mit dem WCF test client: AssetList ListFlaggedAssets(short processCode, string platform, string endpoint = "null", string portalId = "null", int...

Bei der Verwendung von UUIDs, sollte ich auch mit AUTO_INCREMENT?

Wir bauen eine neue web-app, die eine offline-iPad - /Android-app-version auf einer Reihe von lokalen Geräten, die Einsätze mit neuen Daten. Als solche benötigen...

Actionscript-Objekt, das verschiedene Eigenschaften

Wie kann ich die Anzahl der Eigenschaften in einer generischen Actionscript-Objekt? (Wie die Array-Länge) InformationsquelleAutor Fragsworth | 2011-01-15

Wie plot mehrere Graphen und nutzen Sie die Navigations-Taste im [matplotlib]

Die neueste version von matplotlib erstellt automatisch Navigations-buttons unter den graph. Aber die Beispiele, die ich finden alles im Internet zeigen, wie erstellen Sie...