Forum: Compiler & IDEs Unterschiedliche Anzahl von Bits maskieren?


von AVRli (Gast)


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...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

#defien GET_MASK_BIT(N) ((1u << (N)) -1)

Für N = 0 ... 8*sizeof(int)-1

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

AVRli schrieb:
> GET_MASK_BITS(3); gibt nur die ersten 3 Bits zurück.

Du meinst sowas:
1
#define GET_MASK_BITS(x) ((1 << (x)) - 1)

?

edit: OK, Johann war schneller und genauer (an "unsigned" gedacht).

von holger (Gast)


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];
}

von AVRli (Gast)


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...

von Micha (Gast)


Lesenswert?

Rein rechnerisch wäre das.

(2^n)-1

n ist die Anzahl Bits

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von AVRli (Gast)


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...

von bit schieber (Gast)


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 ) )

von Karl H. (kbuchegg)


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

von AVRli (Gast)


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...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Für die high-Bits muss man doch nur die unteren Bits wegschieben:
1
#define MASK_HIGH(N) (-1u << (8-(N)))

von AVRli (Gast)


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...

von Johann L. (gjlayde) Benutzerseite


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

von AVRli (Gast)


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...

von Johann L. (gjlayde) Benutzerseite


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.

von asdf (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.