x ersten bits manipulieren



  • Hallo Leute!

    ich suche nach einer einfachen Möglichkeit eine Anzahl x bits in einer variable zu setzen oder zu clearen.

    Bisher habe ich sowas hier:

    int byte = 0;
    
    for (int i = 0; i < x ; i++)
    {
    
        byte |= 1 << i;
    
    }
    

    Das geht doch bestimmt auch anders und ohne Schleife oder?



  • Du kannst einfach 2x-1 rechnen. Und dann hast du die ersten x Bits auf 1.

    auto mask = (1 << x) - 1;
    
    byte |= mask;
    


  • Skym0sh0 schrieb:

    Du kannst einfach 2x-1 rechnen. Und dann hast du die ersten x Bits auf 1.

    auto mask = (1 << x) - 1;
    
    byte |= mask;
    

    klar kann ich. 🙂

    Danke!



  • Nur aufpassen mit x=32 (oder wie groß auch immer int bei dir ist)!



  • assert(x <= sizeof(int));
    int mask = (1 << x) - 1;
    
    byte |= mask;
    

    Edit: Fail wenn man nicht richtig die Buttons lesen kann 😣



  • sebi707 schrieb:

    Nur aufpassen mit x=32 (oder wie groß auch immer int bei dir ist)!

    ... wollte eigentlich gerade schreiben, dass trotzdem das rauskommen sollte, was man erwartet,
    aber eine kurze Recherche hat ergeben, dass es Undefined Behaviour ist, wenn x >= Anzahl der Bits des zu shiftenden Typs.
    Gut zu wissen, wäre davon ausgegangen dass man alles rausgeshiften kann und dann immer 0 rauskommt.

    Finnegan



  • Skym0sh0 schrieb:

    assert(x <= sizeof(int));
    int mask = (1 << x) - 1;
    
    byte |= mask;
    

    Das assert() ist strenggenommen leider doppelt falsch.
    Einmal falsch da sizeof(int) nicht die Anzahl der Bits eines int zurückgibt.
    Und nochmal falsch weil <= der falsche Test ist. Angenommen int hätte 32 Bit, dann hast du schon bei 32 ein Problem. Bzw. du hast sogar schon bei 31 ein Problem, da du bei 31 ins Vorzeichen reinshiftest, was IIRC nicht erlaubt ist.



  • Skym0sh0 schrieb:

    assert(x <= sizeof(int));
    int mask = (1 << x) - 1;
    
    byte |= mask;
    

    Ob das so funktioniert?

    Sizeof gibt die Groesse in byte zurueck, also vermutlich 4 in dem Fall.

    Ich denke du meintest:

    assert(x <= (sizeof(int)*8));
    

    Bei x = 31 (und nem 32 bit int) kommt es ausserdem bei:

    int mask = (1 << x) - 1;
    

    wahrscheinlich zu einem Überlauf. Setze ich das erste bit auf 1 hab ich bei einer signed integer im Zweierkomplement den wert INT_MIN, -1 davon abziehen ist dann Undefined Behaviour.

    Ich würde folgendes schreiben:

    int mask = 0;
    const int bits = (sizeof(int)*8);
    if (x >= bits){
      mask = (~mask); // dreht alle bits um
    } else {
      mask = (~mask) >> (bits - x); 
    }
    byte |= mask;
    

    Ich bin mal davon aus das man trotzdem alle bits setzen will wenn x groesser der anzahl an Bits ist.

    @FreddyKay
    Um alle gewünschten bits auf 0 zu setzen kannst du dann:

    byte &= (~mask) << bits;
    

    schreiben.

    Etwas leichter gehts übrigens mit uint, da kann ich mit UINT_MAX alles auf 1 setzen und brauch das bitwise not nicht. Ich könnte das zwar auch casten, was aber afaik nicht safe ist, oder MIN_INT benutzen, allerdings weis ich nicht ob das auf wirklich allen Maschinen funktioniert (obs noch Hardware gibt die nicht im Zweierkomplement rechnet weis ich ehrlich gesagt nicht).



  • seelenquell schrieb:

    assert(x <= (sizeof(int)*8));
    

    Ob das so funktioniert?
    std::numeric_limits<int>::digits ist da besser geeignet.



  • roflo schrieb:

    seelenquell schrieb:

    assert(x <= (sizeof(int)*8));
    

    Ob das so funktioniert?
    std::numeric_limits<int>::digits ist da besser geeignet.

    Ah, gut zu wissen 🙂



  • Ihr habt natürlich vollkommen recht. Ich habs nur grad so abändern wollen um richtig cool zu sein, und dann natürlich (zu recht) voll verkackt 😞


Log in to reply