Bits maskieren und dann verschieben



  • Hallo liebe Leute!

    Ich habe mal wieder eine Frage zum Thema Bits 🙂

    Ich möchte mit Hilfe einer Maske jedes 2. Bit aus dataX, von rechts, in einen neuen Wert schreiben.

    Das Resultat sollte folgendermaßen aussehen:

    resultat = 00000111  (7)
    

    Ich habe mir folgenden Code zusammengebastelt, leider funktioniert er so nicht.

    uint64_t maskXvalue = 2;    //0010
    uint64_t data16X = 0;       // 0
    uint64_t dataX = 00101010   //(42)
    
        for(int i=0; i<=32 ; i++) //32 mal jedes 2. Bit
        {
          data16X = dataX & maskXvalue; // 
          data16X >>= 1;         //data16X 1 nach rechts shiften
          maskXvalue <<= 2;  //Maske 2 nach links shiften 
        }
    

    Was habe ich übersehen?



  • @Hamstaaa Du schiebst das Ergebnis ja wieder aus data16X raus.
    Schiebe dataX auf die Position, die du in data16X ändern willst

    @Hamstaaa sagte in Bits maskieren und dann verschieben:

    for(int i=0; i<=32 ; i++) //32 mal jedes 2. Bit

    Das sind 33 Durchläufe.



  • @Hamstaaa sagte in Bits maskieren und dann verschieben:

    uint64_t dataX = 00101010   //(42)
    

    Das nix binär, das oktal. Und es fehlt ein Semikolon. Also zeig den echten code.



  • Warum unbedingt shiften?

    Wenn du konstant mit uint_64 oder uint_32 arbeitest, dann nimm dir doch eine Maske die genauso groß ist.
    Bei jedem zweiten Bit ist das halt 0xAAAAAAAA ( 32bit ).

    Auf die Schnelle mal hingerotzt:

    #include <string>
    #include <iostream>
    
    void showBitString( uint32_t value )
    {
        std::string Text( sizeof( uint32_t ) * 8, '0' );
        uint32_t Bit = 1;
        for ( uint32_t i = 0; i < Text.length(); ++i )
        {
            if ( value & Bit )
                Text[ Text.length() - 1 - i ] = '1';
            Bit <<= 1;
        }
        std::cout << Text << std::endl;
    }
    
    int main()
    {
        uint32_t Source = 12345678, Destination = 0, Mask = 0xAAAAAAAA;
        // Maskierung auf dem ganzen Klotz
        Destination = Source & Mask;
    
        showBitString( Source );
        showBitString( Mask );
        showBitString( Destination );
        return 0;
    }
    


  • @It0101 Warum shiften? Na weil er die Bits "dich" im Ergebnis haben will, ohne die erzwungenen Nullbits dazwischen.



  • uint64_t data16X = 0; // 16?
    uint64_t dataX = 0b101010; // 00101010 ist eine oktale Konstante und sicher nicht dezimal 42
    
        dataX >>= 1; // Erstes zu kopierendes bit auf Position 0 bringen
        for (int i = 0; i < 32 ; i++)
        {
            data16X <<= 1; // Platz machen für das neue Bit im Ergebnis
            data16X |= dataX & 1; // Bit an Position 0 kopieren
            dataX >>= 2; // Nächstes zu kopierendes Bit auf Position 0 bringen
        }
    


  • @hustbaer sagte in Bits maskieren und dann verschieben:

    @It0101 Warum shiften? Na weil er die Bits "dich" im Ergebnis haben will, ohne die erzwungenen Nullbits dazwischen.

    Gut, dann hab ich nicht verstanden worauf der hinaus will 😃



  • @hustbaer sagte in Bits maskieren und dann verschieben:

    uint64_t data16X = 0; // 16?

    • Ja, hat seinen Grund
      Hier soll sozusagen ein uint16_t aus einem uint64_t "extrahiert" werden. Sinn ist es, etwas zu überprüfen.

    uint64_t dataX = 0b101010; // 00101010 ist eine oktale Konstante und sicher nicht dezimal 42

    • sorry 0b101010 war natürlich gemeint
    dataX >>= 1; // Erstes zu kopierendes bit auf Position 0 bringen
    for (int i = 0; i < 32 ; i++)
    {
        data16X <<= 1; // Platz machen für das neue Bit im Ergebnis
        data16X |= dataX & 1; // Bit an Position 0 kopieren
        dataX >>= 2; // Nächstes zu kopierendes Bit auf Position 0 bringen
    }
    

    Danke, das werde ich gleich einmal ausprobieren! 👍🏻

    Jedoch tun sich grade neue Probleme auf, da mein uint64_t aus dem extrahiert werden soll anscheinend in der falschen Richtung gesendet wird 😕

    Probleme über Probleme 😁



  • Warum kein std::bitset?

    #include <bitset>
    #include <climits>
    
    using namespace std;
    
    unsigned int condense_bits( unsigned int input )
    {
       // abhängig davon, welche der Bits aus den jeweils zwei Bits relevant sind kann Mask 0x01, 0x02 oder 0x03 sein
       static unsigned int const Mask = 0x02;
    
       bitset<16> bs;
       for( size_t i = 0; i < sizeof( input ) * CHAR_BIT; i+= 2 )
       { 
          bs[i/2] = (input >> i) & Mask;
       }
       return bs.to_ulong();
    }
    
    int main()
    {
       unsigned int v = condense_bits( 42 );
    }
    

    Edit:
    Wenn du einen uint16_t aus einem uint64_t extrahieren willst dann passt das aber nicht in einen uint16_t.



  • @Hamstaaa sagte in Bits maskieren und dann verschieben:

    Jedoch tun sich grade neue Probleme auf, da mein uint64_t aus dem extrahiert werden soll anscheinend in der falschen Richtung gesendet wird 😕

    Das klingt fast nach Byteorder (Endianness), grade wenn's ums versenden und empfangen via Netzwerk geht. Je nach verwendetem System gib es Funktionen die von Host zu Network Byteorder oder umgekehrt konvertieren.



  • @DocShoe

    std::bitset habe ich auch in Verwendung.

    void printbits(uint64_t number)
    {
        uint64_t chXmask64 = 0xAAAAAAAAAAAAAAAA;
        uint64_t chYmask64 = 0x5555555555555555;
        uint64_t dataX = number & chXmask64;
        uint64_t dataY = number & chYmask64;
            
        std::bitset<40>binX (dataX);
        std::bitset<40>binY (dataY);
        printf("\nX BINARY: "); std::cout << binX << "          X DECIMAL: " << dataX;
        printf("\nY BINARY: "); std::cout << binY << "          Y DECIMAL: " << dataY;
    }
    

    Ich lasse mir damit den Binärcode von dem jeweiligen Kanal ausgeben.

    void magic(uint32_t a, uint32_t b)
    {
      
    uint64_t result64=0;
    uint32_t mask = 1u << 31u;
    
        for (int i=0; i<32; i++) 
        {
          result64 <<= 2;
          result64 |= (!!(a & mask) << 1);
          result64 |= !!(b & mask);
          mask >>= 1;
        }
    printbits(result64);
    }
    

    Wie wäre denn sonst der Code für die andere Byteorder?



  • Ohne dass jetzt unbedingt ein 1:1 Match zu einem Problem auf der Seite bestehen würde...
    Ein Link der bei dem Thema einfach nicht fehlen darf: https://graphics.stanford.edu/~seander/bithacks.html



  • @hustbaer

    Ist schon unter den Lesezeichen gespeichert 🙂



  • @hustbaer sagte in Bits maskieren und dann verschieben:

    uint64_t dataX = 0b101010;

    0b ist kein Standard, nur GCC Extension.



  • @Wutz sagte in Bits maskieren und dann verschieben:

    0b ist kein Standard, nur GCC Extension.

    Da bist du wohl nicht ganz up-to-date.





  • @hustbaer
    C++ interessiert mich nicht, schon gar nicht werde ich diesem quasijährlichen Standardupdatequatsch für essenzielle Basics hinterherlaufen.



  • Bitte liebe Community,

    Ihr kennt ja nun meine Codeschnipsel.

    Ohne noch lange um den heißen Brei zu schreiben, ich komme nicht wirklich weiter. 😫

    Ich möchte der folgenden Funktion 2 uint32_t's geben, die diese dann in einen uint64_t umwandelt, der folgendem Muster entspricht: abababababababab.........

    void magic(uint32_t a, uint32_t b)
    {
      
    uint64_t result64=0;
    uint32_t mask = 1u << 31u;
    
        for (int i=0; i<32; i++) 
        {
          result64 <<= 2;
          result64 |= (!!(a & mask) << 1);
          result64 |= !!(b & mask);
          mask >>= 1;
        }
    }
    

    Das funktioniert auch gut, jedoch kommen die Daten irgendwie in der falschen Reihenfolge an. Die debug Ausgabe ist auch erst mal Nebensache 😤

    Ich benötige für jeden der beiden Werte folgende Bitreihenfolge bedenke: <C2><C1><C0> ist immer 0 0 1; <P> ist ein Paritätsbit. Das errechne ich.

    <P><C2><C1><C0><D15><D14><D13><D12><D11><D10><D9><D8><D7><D6><D5><D4><D3><D2><D1><D0>
    

    Momentan bekomme ich den folgenden String zusammen:

    <D0><D1><D2><D3><D4><D5><D6><D7><D8><D9><D10><D11><D12><D13><D14><D15>
    

    Kann ich die ganze Sache jetzt eleganter lösen als <P><C2><C1> und <C0> hinter <D15> zu ""klemmen" und den gesamten String bei jedem Sendevorgang umzudrehen?

    Ich denke doch das etwas zu CPU intensiv ist auf meinem kleinen ESP32 🙂

    Bitte erbarmt euch meiner 😇



  • Dieser Beitrag wurde gelöscht!


  • @Wutz sagte in Bits maskieren und dann verschieben:

    C++ interessiert mich nicht,

    Weswegen du dich in C++ (alle ISO-Standards) äusserst. Is klar ...


Anmelden zum Antworten