reinterpret_cast von unsigned zu signed



  • Hallo Leute,

    ich habe für mein Problem schon einen Thread gefunden:

    https://www.c-plusplus.net/forum/335247-20

    Und habe den Code von Werner Salomon auf Seite 3 ausprobiert.
    Leider funktioniert er bei mir nicht.
    Auch der Code von GiraffeTurboSetzen funktioniert nicht.

    was mache ich falsch ??

    ich bekomme einen uint8_t buffer.
    daraus ziehe ich mir die Daten, die ich brauche.
    Nun muss ich überprüfen, ob es signed ist.
    Wenn ja, soll umgerechnet werden.

    Im Beispiel habe ich -45 als Zahl.
    aber bei mir kommt immer 4051 raus.

    Könnt ihr mir helfen ?

    void Sig(const uint8_t* buffer) {
        int value = ((buffer[3] & 0x0f)<<8) + buffer[2];
    
    unsigned char* value_str = reinterpret_cast< unsigned char* >(&value);
    auto sign = *reinterpret_cast< std::int16_t* >(value_str);    // save in signed
    cout << "value" << sign << endl;
    }
    


  • okay, wenn ich es so abändere:

    auto sign = *reinterpret_cast< std::int8_t* >(value_str);
    

    funktioniert es.

    Aber ab einem Wert von 0xf80 --> -128
    alle werte die kleiner sind, da springt er wieder ins positive.

    ich denke, dass daran, dass es int8_t ist und nicht int16_t,
    aber mit int16_t funktioniert es nicht, da konvertiert er es nicht ins negative.

    😕 😕



  • Hallo!

    Zum besseren Verständnis von Umwandlungen dieser Art hilft es zu wissen, dass das Vorzeichen im letzten bzw. ersten Bit des jeweiligen Bitrahmens gespeichert wird.
    Welches von beiden genutzt wird, hängt von der vom System genutzten Bit-Reihenfolge ab.
    Siehe hierzu auch
    http://stackoverflow.com/questions/3894262/little-endian-signed-integer

    Bei dem vorliegenden Umwandlunganforderung von uint8_t nach int16_t ist also zu prüfen, ob das letzte bzw. erste Bit 1 oder 0 ist.
    Ist es 1, so liegt ein negativer Wert vor.
    Damit man den korrekten Zahlenwert aus uint8_t bekommt, muss man in der uint8_t-Variable das Vorzeichenbit auf null setzen.
    Danach muss man den auf int16_t konvertierten Zahlenwert negieren, wenn das Vorzeichenbit 1 war.

    Gruß, Lothar.



  • Wie groß sind deine Eingabe Daten? Ich tippe mal 12 Bit weil du du nur 4 Bits von buffer[3] mitnimmst. Dann ist dein Kram mit dem reinterpret_cast Quatsch, denn das funktioniert wenn überhaupt nur für 8, 16, 32 oder 64 Bit aber selbst dann würe man lieber einen static_cast nehmen (ja ich weiß ist eigentlich undefined-behaviour). Du musst also selbst schauen ob das entsprechende Bit gesetzt ist. Das macht dieser Code aus dem anderen Thread:

    // Anpassung für negative Zahlen von GiraffeTurboSetzen
    const int valueBits = 12;
    if(value & (1 << (valueBits - 1)))
      value -= 1 << valueBits;
    

    Hast du das schon ausprobiert?



  • hallo,

    danke für die tolle Erklärung.

    Ja, das habe ich auch schon ausprobiert, leider ohne Erfolg.
    ich bekomme wieder nur die positive zahl.

    Es muss auch allgemeingültig sein ...
    ich habe das beispiel sehr vereinfacht.
    normal kann mein Wert zwischen 1 und 16 bit sein.
    Deswegen wollt ich es in ein int16_t konvertieren, weil dann alles abgedeckt sein müsste



  • Ergänzung.

    Bitte nicht wundern 🙂

    Ich habe jetzt gleich Feierabend und darf meinen Laptop nicht mit nachhause nehmen.
    ich werde also vor Montag früh nicht antworten können bzw. Vorschläge ausprobieren können.

    Dennoch vielen Dank im Voraus für alle Hilfen, ich melde mich am Montag wieder 🙂



  • zimtikus schrieb:

    Es muss auch allgemeingültig sein ...
    ich habe das beispiel sehr vereinfacht.
    normal kann mein Wert zwischen 1 und 16 bit sein.
    Deswegen wollt ich es in ein int16_t konvertieren, weil dann alles abgedeckt sein müsste

    Dann ist die Lösung von GiraffeTurboSetzen ja eigentlich optimal. Da brauchst du nur valueBits anzupassen für verschieden viele Bits. Kannst du mal ein Beispiel mit Daten geben für die die Methode nicht das von dir erwartete Ergebniss liefert? Ich bin mir nämlich ziemlich sicher das die Lösung korrekt ist.



  • zimtikus schrieb:

    okay, wenn ich es so abändere:

    auto sign = *reinterpret_cast< std::int8_t* >(value_str);
    

    funktioniert es.

    Aber ab einem Wert von 0xf80 --> -128
    alle werte die kleiner sind, da springt er wieder ins positive.

    ich denke, dass daran, dass es int8_t ist und nicht int16_t,
    aber mit int16_t funktioniert es nicht, da konvertiert er es nicht ins negative.

    😕 😕

    Punkt 1: erkläre dein Problem genauer. Du sagst nur, Code xy funktioniert bei dir nicht. Na und? Welche Eingangsdaten hast du, und was erwartest du als Ausgabe? Dann kann man überlegen wie man das löst und im letzten Schritt kann man anfangen, Code zu schreiben, der auf irgendwelche Bits zugreift.

    Punkt 2: sobald es bei den Integer Datentypen Richtung Überlauf geht, ist immer große Verwunderung was da passiert.
    Am besten man macht sich frei von dem Rechnen, wie man es in der Schule gelernt hat: der Computer rechnet nämlich nicht auf den ganzen Zahlen, sondern nur auf einer Teilmenge davon, z.B. 0...255!
    Stattdessen rechnet man in einem sogenannten Restklassenring, bei 8bit=256 Werte rechnet man also stets modulo 256.
    Das heißt aber auch:
    (0=256=512=...=-256=-512=...) modulo 256 weil ja z.B. 256 modulo 256=0
    (1=257=513=...=-255=...) modulo 256
    (255=511=...=-1=...) modulo 256
    (254=...=-2=...) modulo 256
    (253=...=-3=...) modulo 256

    Das heißt, ob man nun z.B. mit 255 oder mit -1 rechnet macht absolut keinen Unterschied! Der Computer rechnet absolut gleich, erst wenn es zur Ausgabe kommt wird durch z.B. printf unterschieden wie man das Bitmuster interpretieren und ausgeben soll: entweder als 255 oder als 255-256=-1.

    Du siehst: man kann sich nun selbst aussuchen, wie man nun die Zahlen benennt: manchmal ist es besser, das Bitmuster x als 255 zu benennen, das andere mal ist es besser, es als -1 zu benennen. Am Computer wird das eben so gemacht, dass alle Bitmuster mit einer 1 an der höchstwertigen Stelle als negative Zahl interpretiert werden.
    Hat deine Zahl N bit (in deinem Fall 12bit?), dann ist die erste Zahl, die negativ benannt ist, 2(N-1)=211.
    Ist deine zu einem unsigned int zusammengebaute Zahl nun größer oder gleich 2^11, so handelt es sich um eine negative Zahl. Der Zahlenwert ist dann 2^12-Zahl.

    Beispiel bei unsigned char(8bit):
    du liest die Zahl 150 ein. Diese ist größer gleich 2^7=128, somit ist die Zahl als negativ zu interpretieren. Die signed char Zahl ist also 150-256=-106. Willst du den Zahlenwert, so macht du eben 256-150=106 und schreibst davor noch ein "-" davor bei der Ausgabe ... du kannst also komplett ohne den unsigned char Bereich zu verlassen auch mit negativen Werten rechnen bzw. diese ausgeben.



  • Hallo,

    danke für die vorschläge.

    ja, ich frage jetzt das MSB ab, ob es gesetzt ist und wenn ja, dann rechne ich es um.

    int power = pow(2,sigLen-1);
    if( (value & power) == power ) {
    			int power2 = pow(2,sigLen);
    			x = value - power2;
    		}
    		else { // value is unsigned --> no action required
    			x = (int)value;
    		}
    


  • Und das funktioniert jetzt? Weil das ist genau die Lösung zu der ich schon ganze Zeit rate. Du weißt, dass pow(2,x) das gleiche liefert wie 1 << x ?



  • Hallo,

    ähm, nein leider nicht 😞

    das tut mir leid. ich weiß auch nicht, aber als ich es so kopiert hatte, hatte es nicht funktioniert.



  • zimtikus schrieb:

    Hallo,

    ähm, nein leider nicht 😞

    das tut mir leid. ich weiß auch nicht, aber als ich es so kopiert hatte, hatte es nicht funktioniert.

    was willst du überhaupt?
    Definiere Input, Output und gewünschtes Verhalten. Du postest in unregelmäßigen Abständen irgendeinen Code, der "nicht funktioniert", ohne überhaupt mal klarzustellen, was du willst.
    So wird das nichts. Das ist reines Copy and Pase Engineering was du hier betreibst.


Log in to reply