Spaß mit Bits



  • unsigned char gepackt; // <- Dein Konstrukt
    unsigned char echt;
    
    // Lesen:
    // 0-4
    echt = gepackt & 0x1F;
    // 5-6
    echt = (gepackt >> 5) & 0x03;
    // 7
    echt = gepackt >> 7;
    
    // Setzen:
    // 0-4
    gepackt = (gepackt & 0xE0) | echt; // zur Sicherheit auch: "| (echt & 0x1f)"
    // 5-6
    gepackt = (gepackt & 0x9F) | (echt << 5); // zur Sicherheit auch: "| ((echt & 0x03) << 5)"
    // 7
    gepackt = (gepackt & 0xEF) | (echt << 7); // zur Sicherheit auch: "| ((echt & 0x01) << 7)"
    

    Unsigned ist wichtig für's Rechtsshiften.

    Hab's nicht getestet. Hoffe, es stimmt alles.
    Aber vielleicht gehts ja noch einfacher?



  • Für das erste Ding brauchst du ab dem ersten Bit fünf Stück:
    (c>>0) & ((1<<5)-1)

    Für das zweite Ding brauchst du ab dem sechsten Bit zwei Stück:
    (c>>5) & ((1<<2)-1)

    Für das dritte brauchst du ab dem achten Bit eins:
    (c>>7) & ((1<<1)-1)



  • Ich das nun der Einfachheit mal mit nur 2 Werten versucht. Das Auslesen klappt sehr gut, aber das setzen nicht.

    #include <iostream>
    
    #define MASK_BIT1 (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4)
    #define MASK_BIT2 (1 << 0 | 1 << 1 | 1 << 2)
    
    int get_bits1(unsigned char c)
    {
    	// Start: 11111111
    
    		     // => 76543210
    	c >>= 3; // => 00011111
    
    	return c & MASK_BIT1;
    }
    
    int get_bits2(unsigned char c)
    {
    	// Start: 11111111
    
    			 // => 76543210
    	c >>= 5; // => 00000111
    
    	return c & MASK_BIT2;
    }
    
    void set_bits1(unsigned char& c, unsigned char val)
    {
    	// Start: 
    	//	c = 00000000
    	//	val = 00011111
    
    	c = (val & MASK_BIT1) | (c << 3); // ???
    }
    
    void set_bits2(unsigned char& c, unsigned char val)
    {
    }
    
    int main()
    {
    	unsigned char c = 0;
    
    	set_bits1(c, 24);
    	set_bits2(c, 6);
    
    	std::cout << get_bits1(c) << std::endl;
    	std::cout << get_bits2(c) << std::endl;
    
    	return 0;
    }
    

    Ich würde gerne den Wert von val in die entsprechenden Bits schreiben. Leider kommen nicht wieder die Werte raus, die ich übergeben habe. Ich hatte es einmal geschafft, das zumindest set_bits1 klappt, aber set_bits2 hat die Werte wieder kaputt gemacht. Ich hab jetzt so viele Varianten ausprobiert... Hier fehlt mir wieder das Verständnis.



  • void set_bits1(unsigned char& c, unsigned char val)
    {
        c |= val;
    }
    
    void set_bits2(unsigned char& c, unsigned char val)
    {
        c |= val<<5;
    }
    


  • Da kommen leider auch nicht die korrekten Werte bei raus.



  • Ich kriegs einfach nicht hin... Den ersten Wert kriege ich meistens noch gesetzt, aber sobald ich den zweiten setze manipuliert dies den ersten...

    Es ist zum Heulen.



  • ghjghj schrieb:

    Zugreifen möchte ich im Byte auf folgende Bits:
    Bit 1-5 (Wertbereich 0-32)
    Bit 6-7 (Wertbereich 0-4)
    Bit 8 (Wertbereich 0-1)

    FALSCH!

    Bit 0-4 (Wertbereich 0-31)
    Bit 5-6 (Wertbereich 0-3)
    Bit 7 (Wertbereich 0-1)

    int main()
    {
    	unsigned char bit0bis4 = 31, bit5und6 = 2, bit7 = 1;
    
    	unsigned char gepackt;
    
    	gepackt = bit0bis4 | bit5und6<<5 | bit7<<7; // alle eingepackt
    
    	bit0bis4 = gepackt&0x1f;           // bit0bis4 ausgepackt
    	bit5und6 = (gepackt&0x60)>>5;      // bit5und6 ausgepackt
    	bit7 = gepackt>>7;                 // bit7 ausgepackt
    	return 0;
    }
    

    😉



  • Oh, du hast natürlich recht mit den Wertbereichen. Ich hab die 0 zwar hingeschrieben, aber beim Zählen nicht beachtet. Dein Beispiel ist jedenfalls echt super. Könntest du mir das auch noch auf mein anderes Beispiel umsetzen?

    #include <iostream>
    
    #define MASK_BIT1 (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4)
    #define MASK_BIT2 (1 << 0 | 1 << 1 | 1 << 2)
    
    int get_bits1(unsigned char c)
    {
        // Start: 11111111
    
                 // => 76543210
        c >>= 3; // => 00011111
    
        return c & MASK_BIT1;
    }
    
    int get_bits2(unsigned char c)
    {
        // Start: 11111111
    
                 // => 76543210
        c >>= 5; // => 00000111
    
        return c & MASK_BIT2;
    }
    
    void set_bits1(unsigned char& c, unsigned char val)
    {
     // ???
    }
    
    void set_bits2(unsigned char& c, unsigned char val)
    {
     // ???
    }
    
    int main()
    {
        unsigned char c = 0;
    
        set_bits1(c, 24);
        set_bits2(c, 6);
    
        std::cout << get_bits1(c) << std::endl;
        std::cout << get_bits2(c) << std::endl;
    
        return 0;
    }
    

    Das Auslesen habe ich inzwischen hinbekommen, aber beim Setzen hapert es. Es ist mir einfach nicht klar, wie ich es schaffe die entsprechenden Bits zu setzen ohne die anderen Bits zu beeinflussen und damit die anderen Werte zu verfälschen.



  • Zeig' doch mal Deinen aktuellen Code - also nicht den von eben, sondern den, der "die anderen Bits beeinflußt".



  • ghjghj schrieb:

    Es ist mir einfach nicht klar, wie ich es schaffe die entsprechenden Bits zu setzen ohne die anderen Bits zu beeinflussen und damit die anderen Werte zu verfälschen.

    Mit dem Operator | bzw |=



  • Ist dir die Bitlogik überhaupt klar? Weißt Du, was |, &, ~, ^ machen?



  • Wie soll man Dir denn helfen, Deine Probleme zu identifizieren, wenn Du Deinen Code nicht rausrückst?



  • #include <iostream>
    #include <cassert>
    
    #define MASK_BIT1 (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4)
    #define MASK_BIT2 (1 << 0 | 1 << 1 | 1 << 2)
    
    int get_bits1(unsigned char c)
    {
    	// Start: 11111111
    
    		     // => 76543210
    	c >>= 3; // => 00011111
    
    	return c & MASK_BIT1;
    }
    
    int get_bits2(unsigned char c)
    {
    	// Start: 11111111
    
    			 // => 76543210
    	c >>= 5; // => 00000111
    
    	return c & MASK_BIT2;
    }
    
    void set_bits1(unsigned char& c, unsigned char val)
    {
    	c = c | val << 3;
    }
    
    void set_bits2(unsigned char& c, unsigned char val)
    {
    	// Nehme ich folgenden Teil mit rein, dann ist der andere Wert, welcher mit set_bits1 festgelegt wurde plötzlich falsch
    
    	//c = c | val << 5;
    }
    
    int main()
    {
    	unsigned int total = 0;
    	unsigned int wrong = 0;
    
    	for (unsigned int i = 0; i <= 31; ++i)
    	{
    		for (unsigned int j = 0; j <= 7; ++j)
    		{
    			unsigned char c = 0;
    
    			set_bits1(c, i);
    			set_bits2(c, j);
    
    			++total;
    
    			if (get_bits1(c) != i || get_bits2(c) != j)
    			{
    				++wrong;
    
    				//continue;
    			}
    
    			std::cout << i << " = " << get_bits1(c) << std::endl;
    			std::cout << j << " = " << get_bits2(c) << "\n" << std::endl;
    		}
    	}
    
    	std::cout << total - wrong << " of " << total << std::endl;
    
    	return 0;
    }
    

    Der Aufruf von set_bits2 macht den mit set_bits1 gesetzten Wert zu nichte.



  • #include <iostream>
    
    int get_bits1(unsigned char c) // Bit 0 bis 4
    {
        return c&0x1f;
    }
    
    int get_bits2(unsigned char c)
    {
        return (c&0x60)>>5;
    }
    
    void set_bits1(unsigned char& c, unsigned char val) // Bit 5 und 6
    
    {
    	c &= 0xe0;
    	c |= val;
    }
    
    void set_bits2(unsigned char& c, unsigned char val)// val 0 bis 3 !
    {
        c &= 0xf9;
    	c |= val<<5;
    }
    
    int main()
    {
        unsigned char c;
    
        set_bits1(c, 24);
        set_bits2(c, 3);
    
        std::cout << get_bits1(c) << std::endl;
        std::cout << get_bits2(c) << std::endl;
    
        return 0;
    }
    

    😉



  • Ändert man aber z.B. set_bits1(c, 24); auf set_bits1(c, 12); dann passt es wieder nicht... Und genau hier liegt ständig mein Problem. Es ist nie allgemeingültig und funktioniert nicht immer zuverlässig.





  • Das hat jetzt aber mit deinem Eingangspost wenig zu tun:

    Zugreifen möchte ich im Byte auf folgende Bits:
    Bit 1-5 (Wertbereich 0-32)
    Bit 6-7 (Wertbereich 0-4)
    Bit 8 (Wertbereich 0-1)

    einGasts Korrektur unbenommen.

    get_bits1() gibt Dir die fünf obersten Bits von c.
    get_bits2() gibt Dir die drei obersten Bits von c.
    Das überschneidet sich.

    Genauso überschreiben set_bits1() u. set_bits2() sich gegenseitig

    Du wolltest doch a) die ersten fünf, b) die nächsten zwei und c) das letzte eine Bit.
    Also das, was ich vorhin anbot, oder funktionierte das nicht?



  • @einGast:

    in Deiner set_bits2() meist Du - glaube ich:

    &=0x9F;
    

    Oder verrenne ich mich hier?



  • ghjghj schrieb:

    Ändert man aber z.B. set_bits1(c, 24); auf set_bits1(c, 12); dann passt es wieder nicht... Und genau hier liegt ständig mein Problem. Es ist nie allgemeingültig und funktioniert nicht immer zuverlässig.

    Da ist ein Zahlendreher drinn 0xf9, es muss 0x9f heißen, also

    #include <iostream>
    
    int get_bits1(unsigned char c) // Bit 0 bis 4
    {
        return c&0x1f;
    }
    
    int get_bits2(unsigned char c)
    {
        return (c&0x60)>>5;    // Bit 5 und 6
    
    }
    
    void set_bits1(unsigned char& c, unsigned char val) // Bit 0 bis 4
    
    {
    	c &= 0xe0;
    	c |= val;
    }
    
    void set_bits2(unsigned char& c, unsigned char val)// val 0 bis 3 !
    {
        c &= 0x9f;
    	c |= val<<5;
    }
    
    int main()
    {
        unsigned char c;
    
        set_bits1(c, 24);
        set_bits2(c, 2);
    
        std::cout << get_bits1(c) << std::endl;
        std::cout << get_bits2(c) << std::endl;
    
        return 0;
    }
    

    Probier es!



  • Caligulaminus schrieb:

    @einGast:

    in Deiner set_bits2() meist Du - glaube ich:

    &=0x9F;
    

    Oder verrenne ich mich hier?

    Du hast Recht, hab den Wert vom Hexrechner verdreht übernommen. 🙂


Anmelden zum Antworten