Unterschiedliche Anzahl von Bits maskieren?

Gast #2849141
Lesenswert?

Hallo,

ich lege mir hier gerade die Karten, auf dem Papier weiß ich was ich 
machen möchte aber es in C umzusetzen da stehe ich gerade auf dem 
Schlauch.

Ich möchte eine bestimmte Anzahl von Bits maskieren die im 
Programmablauf dynamisch ist und eben von 1-8 Bits sein kann.

Wie ich 3 Bits maskiert ist mir klar...
1
  uint8_t a,b;
2

3
  ...
4
  b = 0b00001101;
5
  a = b & 0b00000111;
6
  ...

a sollte dann 0b00000101 sein...

Wie stelle ich das nun an wenn ich x Bit maskieren möchte?
Ergebniss soll dann sein das man per Parameter die Bits maskiert 
GET_MASK_BITS(3); gibt nur die ersten 3 Bits zurück...

Macht man das mit einen switch/case Block?

Grüße AVRli...
Gast #2849186
Lesenswert?

>Bits maskieren die im
>Programmablauf dynamisch ist

>GET_MASK_BITS(3);

uint8_t GET_MASK_BITS(uint8_t n)
{
 uint8_t mask[] = {0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};

 if((n - 1) > 7) return 0;

 return mask[n-1];
}
Gast #2849720
Lesenswert?

Vielleicht habe ich mich auch unglücklich ausgedrückt, doch das was 
holger beschrieben hat, ist das was ich gesucht habe. Das ganze habe ich 
mir nun nochmal für die andere Richtung geschrieben...
1
uint8_t get_mask_bits_from_msb(uint8_t n) {
2
  uint8_t mask[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF};
3
  if (n==0) return 0;
4
  if((n - 1) > 7) return 0;
5
  return mask[n-1];
6
}

Grüße AVRli...
Moderator Persönliche Seite #2849860
Lesenswert?

AVRli schrieb:
> Vielleicht habe ich mich auch unglücklich ausgedrückt,

Nein.

> doch das was
> holger beschrieben hat, ist das was ich gesucht habe.

Das, was Johann und ich geschrieben haben, ist es dann auch. ;-)

Holger benutzt halt eine tabellenbasierten Ansatz, Johann und ich
einen arithmetischen.  Die Tabelle ist schneller, braucht aber
bei größeren zulässigen Operanden schnell viel Platz.
Gast #2850371
Lesenswert?

Habe mir das nun nochmal angesehen und auch für die LSB Variante 
verstanden wie der rechnerische Weg ist... das ist auch recht elegant!!!
Ich habe es auf dem ersten Blick nur so gesehen das man das einzelne Bit 
zurück bekommt.

Durch Euren Schuppser nun erkannt das durch das -1 dann die maskierten 
die richtige Rückgabe sind... gut gut!

Habe mich dann für diesen Weg entschieden da ich den RAM noch brauche...

Wieder was gelernt! ;-)

Aber ganz ehrlich die andere Richtung bekomme ich so nicht hin... ich 
habe wohl meine Schwierigkeiten mit der Bit- Manipulation...



Gruß AVRli...
Gast #2850403
Lesenswert?

Einfach auf die andere seite schieben ;-)

Wobei das dann natürlich davon abhängig ist wie groß der Zielwert ist.

Für uint8_t:
1
#define GET_MASK_BIT(N) ( ( ( 1u << ( N ) ) -1 ) << ( 8 - N ) )
#2850408
Lesenswert?

AVRli schrieb:

> Aber ganz ehrlich die andere Richtung bekomme ich so nicht hin...

kleiner Tip.

Wenn du in einem Byte nur die untersten 5 Bits auf 1 hast, dann sind 
logischerweise die obersten 3 Bits auf 0  (weil 5 + 3 wieder die 8 Bits 
in einem Byte ergeben).
Dreht man dann in dem so erhaltenen Byte die Bits einfach alle um, dann 
hat man ein Byte, bei dem die obersten 3 Bits auf 1 sind und die unteren 
5 Bits auf 0.

Um also ein Byte zu erhalten, bei dem die obersten n Bits auf 1 sind, 
genügt es sich ein Byte zu machen, bei dem die unteren (8-n)Bits auf 1 
sind und dann einfach alle Bits umzudrehen.
Und wie man sich ein Byte macht, bei dem die unteren m Bits auf 1 sind, 
dafür hast du ja schon eine Funktion :-)

Bsp. Du brauchst ein Byte, bei dem die oberen 2 Bits auf 1 sind.

Zu erzeugen ist also                      0b11000000
------------------------------------------------------
Dazu erzeugst du dir ein Byte,
bei dem die unteren 6 Bits auf 1 sind     0b00111111
und drehst alle Bits um                   0b11000000
Gast #2850664
Lesenswert?

Vielen Dank an Euch!

Als erstes habe ich versucht mit einer "Spiegelung zum Erfolg zu kommen 
doch das war nichts... für Euch sicher logisch, ich vermute es geht 
nicht weil man bei 8 Bit theoretisch 9 braucht und deshalb bei 8 eine 0 
zurück kommt.
1
  #define GET_MASK_BIT_MSB(N) (~((1u << (N)) -1))

Dann habe ich den Vorschlag von "bit schieber" probiert, den habe ich 
auch verstanden, doch da muss mana auch erstmal drauf kommen... ;-)

Many Thanks!!! AVRli...
Gast #2850781
Lesenswert?

Ja das funktioniert nun... mit bit schieber sein #define ging es auch 
nicht so ganz... warum kann ich nicht erklären... mit der Zeile klappt 
es wie ich es erwartet habe doch wenn ich ganz ehrlich bin grübel ich 
noch über den Wert

-1u

heißt -1 nicht das es signed ist und das u das es unsigned sein 
soll... grübel

Gruß AVRli...
Persönliche Seite #2850821
Lesenswert?

-1u ist ein unsigned, der alle Bits gesetzt hat. Alternativ geht auch

UINT_MAX aus limits.h oder, falls 16-Bit int, UINT16_MAX aus stdint.h

Um zB eine Maske zu bekommen, die jedes 3. Bit gesetzt hat, kann man 
einfach
1
unsigned long mask_jedes_3te_bit = -1ul / 7; // 0x24924924

oder eine Maske, die abwechselnd immer 3 Bits gesetzt und leer hat:
1
unsigned long mask_mit_3er_paketen = -1ul / 9; // 0x1C71C71C
Gast #2851210
Lesenswert?

Vielen Dank für die Erklärung!
Ich sehe das ich es viel umständlicher lösen würde, wenn ich das mal 
benötigen würde. Ich hätte mir ein Byte genommen und mein Bitmuster mit 
Zählern rein geschoben. Das es auch so geht war mir nicht klar.

Wie man auf die passenden Teilungswerte kommt habe ich nach langen 
probieren auch herausgefunden.

jedes 5 Bit gesetzt...
1
unsigned long mask_jedes_5te_bit = -1ul / 1F; // 0x8421084

und 5er Pakete...
1
unsigned long mask_mit_5er_paketen = -1ul / 1F; // 0x7C1F07C

Nur ganz ehrlich... nicht lachen Warum das so klappt ist mir ein 
Rätsel... :-D

Grüße AVRli...
Persönliche Seite #2851274
Lesenswert?

AVRli schrieb:
> Nur ganz ehrlich... nicht lachen Warum das so klappt ist mir ein
> Rätsel... :-D

Es beruht auf folgender Faktorisierung:
Oben ist b=2, d.h. es ist für Zahlen in Binärdarstellung, aber die 
Faktorisierung geht genauso für alle anderen b-ären Darstellungen.

Z.B ist 111111 immer durch 111 und duch 11 teilbar, unabhängig vom 
Zahlensystem, in dem diese Zahlen dargestellt sind.
Moderator #2855342
Lesenswert?

asdf schrieb:
> Johann L. schrieb:
>> unsigned long mask_jedes_3te_bit = -1ul / 7; // 0x24924924
>
> Hm, wobei mich das -1u oder -1ul auch eher irritieren würde.
>
> Warum nicht 0xffff oder 0xffffffff etc. je nach Anzahl Bits, dann ist
> sofort klar dass es ein uint16_t/uint32_t mit allen Bits auf 1 gesetzt
> ist.

Da muss man aber erst die 'f's nachzählen. Bei 16 Bit ist das noch
leicht, bei 32 Bit schon etwas ungemütlich und bei 64 Bit ziemlich
fehlerträchtig ;-)

Wenn dich nur die Negation des unsigned-Werts stört, kannst du auch
1
unsigned long mask_jedes_3te_bit = ~0ul / 7; // 0x24924924

schreiben.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren