Signed to Unsigned int



  • Sorry C++Greenhorn, aber das wird ja immer abstruser, was du schreibst.
    Du scheinst, wie sebi707 schon geschrieben hat, überhaupt nicht zu verstehen (oder es nicht richtig hier formulieren zu können), wie Daten gespeichert werden (intern gibt es nur binär - alles andere, was du beschreibst, ist lediglich eine (menschliche) Interpetation der Daten).

    Was für ein Wert soll jetzt "0110" darstellen? Und wieso erhältst du diesen als String (denn nur dann machen deine Aussagen halbwegs Sinn)?
    Und wer intepretiert ("mein Interpreter") diesen Datenwert???

    Ich dachte, du redest von einem CAN-Bus Signal (bzw. Message) und dann wäre es einfach eine Bit-(bzw. Byte-)Folge.
    Auch wenn deine externe Library dir den Wert als tU32 übergibst, die Interpretation mußt du dann schon selber durchführen. Und wie ich schon schrieb, wäre dann z.B. ein Bitfeld dafür passend.

    PS: Negative und positive Zahlen sind auch nur eine Interpretation der Daten (welche nur bei mathematischen Operationen oder einer Ausgabe relevant sind).



  • .. man sollte ja gar nicht meinen, wie schwierig so eine Bit-Popelei ist.

    Folgender Code funktioniert nur, wenn Du Dich auf einem little endian System befindet (z.B. Windows) und die 12-Bit-Zahl ganz vorn im Telegramm steht:
    Weiter nehmen ich an, dass die Quelle ein big endian-System ist. -145 ist ein schlechtest Beispiel, da sie in 12Bit spigelsymmetrisch ist, daher hab ich -146 genommen!

    #include <iostream>
    #include <cstdint>      // std::uint32_t, int16_t
    #include <algorithm>    // std::reverse
    using namespace std;
    
    typedef std::uint32_t tU32;
    void SignalKommt( tU32 u32Value )
    {
        cout << "Value: " << u32Value << endl;
        cout << "Value: 0x" << hex << u32Value << dec << endl;
    
        unsigned char* beg = reinterpret_cast< unsigned char* >( &u32Value );
        std::reverse( beg, beg + 2 ); // Byte-Reihenfolge auf little endian bringen
        auto zahl = *reinterpret_cast< std::int16_t* >( beg );    // in signed Zahl ablegen;
        zahl >>= 4;  // auf 16 Bit bringen
        cout << "Ergebnis: " << zahl << endl;
    }
    int main()
    {
        using namespace std;
                           // 1111 0110  1110 ... soll eine -146 sein!
        unsigned char can[] = { 0xf6, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };   // das CAN-Telegramm
        tU32 u32Value = *reinterpret_cast< const tU32* >( can );
        SignalKommt( u32Value );
        return 0;
    }
    

    Output:

    Value: 57590
    Value: 0xe0f6
    Ergebnis: -146



  • C++_Greenhorn schrieb:

    Ich bekomme von meinem Bus eine Integer-Zahl, die jedoch keine übliche
    Interpretation zulässt. Wenn ich ein int value = 0110 bekomme, versteht in diesem
    Fall mein Interpreter durch die vorangestellt „0“ einen Hexadezimal-Wert und würde
    mir bei einer Ausgabe ohne weiteres Zutun den Wert 272 (also 0x0110 zu 272
    dezimal) ausgeben. Habe ich keine führende Null besteht das Problem
    beispielsweise nicht, aber trotzdem hätte ich z.B. bei einem int value = 1100 eben
    dezimal den Wert 1100, obwohl ich diesen als 0b110 = 12 dezimal verarbeiten muss.
    Hierfür konnte ich mir durch geeignetes maskieren eine Funktion schreiben, die
    diese Problem löst.

    Wie schon mehrfach erwähnt, sind das alles Erfindungen deinerseits. Zahlen werden ausschließlich binär gespeichert und verarbeitet. Wenn du mit std::cout eine dezimale Ausgabe siehst, dann liegt das nicht etwa daran, dass sie irgendwie "dezimal gespeichert wurde", sondern daran, dass während der Ausgabe mehrfach durch 10 geteilt wird und so die einzelnen Dezimalstellen errechnet werden.

    Kehren wir zu deinem Beispiel mit 3951 und -145 zurück.
    Tatsache ist offenbar, dass dir der Wert in einer 32 bit-Variable übergeben wird.

    Du hast also folgendes - die niederen 12 bit sind gesetzt, der Rest sind Nullen:
    uVal=00000000000000000000111101101111

    Dein Problem ist, dass das höchste Bit (fett markiert) im Kontext eines unsigned 32 bit-Typen die Wertigkeit 2048 hat. Da du das aber als 12 bit-Zahl im Zweierkomplement interpretieren möchtest, wäre -2048 korrekt. Ergo musst du 2048-(-2048)=4096 wieder abziehen.

    Da du eine vorzeichenbehaftete Zahl darstellen willst:

    int32_t sVal=uVal;
    

    Es hat sich nichts verändert, außer dass das höchste Bit nun die Wertigkeit -2147483648 statt +2147483648 hat. Ist egal, weil dieses Bit immer 0 ist, wenn deine Zahl kürzer als 32 bit ist. Wenn nicht, bist du hiermit fertig und musst den nächsten Schritt überspringen (der würde im Falle von valueBits==32 undefined behavior verursachen).

    const int valueBits=12;
    if (uVal&(1<<(valueBits-1))) { //höchste Bit gesetzt?
        sVal-=1<<valueBits; //4096 abziehen
    }
    

    Als Ergebnis hast du nun den gewünschten Wert -145. Binär sieht das nun so aus:
    11111111111111111111111101101111
    Letzendlich hast du eine 12 bit-Zahl im Zweierkomplement durch eine sign extension auf eine 32 bit-Zahl im Zweierkomplement erweitert - genau das, was erreicht werden sollte.



  • Werner Salomon schrieb:

    .. man sollte ja gar nicht meinen, wie schwierig so eine Bit-Popelei ist.

    Ich weiß nicht ob der folgende Code als negativ Beispiel gedacht war oder dem TO helfen sollte. Jedenfalls werden dort viele Annahmen gemacht, die nicht überall zutreffen. Das es nur auf einem Little Endian System läuft hast du ja selbst schon erkannt. Der Shift nach rechts von einem signed Integer ist auch nicht festgelegt. Besser den Code von GiraffeTurboSetzen nutzen.



  • sebi707 schrieb:

    Besser den Code von GiraffeTurboSetzen nutzen.

    blöd bloß, dass der nicht funktioniert, wenn beide Systeme unterschiedlichen Endian haben. Der OP scheint auch der Meinung zu sein, dass das bei ihm nicht funktioniert.

    @sebi707: Mach Du doch doch mal einen Vorschlag, wie man die Zahl Endian-sicher auslesen kann.



  • Die Anpassung von GiraffeTurboSetzen macht gar nichts mit der Endianness weil das schon den Schritt davor passiert sein sollte. So könnte der Schritt davor platformunabhängig aussehen:

    uint8_t can[] = { 0xf6, 0xe0 };
    int value = can[0] << 4 | can[1] >> 4;
    
    // Anpassung für negative Zahlen von GiraffeTurboSetzen
    const int valueBits = 12;
    if(value & (1 << (valueBits - 1)))
      value -= 1 << valueBits;
    

    Wenn die gesendeten Daten Little Endian sind tauscht man eben can[0] und can[1] .


Anmelden zum Antworten