Forum: Mikrocontroller und Digitale Elektronik Bitmanipulation


von Karl (Gast)


Lesenswert?

Hallo
Versuche gerade das Thema Bitmanipulation durchzuarbeiten und zu 
verstehen.
Auf dieser Seite 
https://www.mikrocontroller.net/articles/Bitmanipulation
steht das so:
1
#define MEINBIT15 15
2
#define MEINBIT42 42
3
4
uint32_t reg_32; /* uint32_t definiert per typedef z. B. in stdint.h */
5
uint64_t reg_64; /* uint64_t definiert per typedef z. B. in stdint.h */
6
7
reg_32 |= (1 << MEINBIT15);              /* FEHLER: Setzt die Bits 31 - 15, da ((int)1 << 15) == 0xFFFF8000 */
8
9
reg_32 |= ((uint32_t)1 << MEINBIT15);    /* Hier wird nur Bit 15 gesetzt. */
10
reg_32 |= (1U << MEINBIT15);             /* */
11
reg_32 |= (1L << MEINBIT15);             /* andere Schreibweise. */
12
reg_64 |= (1LL << MEINBIT42);            /* Hier wird nur Bit 42 gesetzt,
13
                                            andere Schreibweise für 64 Bit (long long). */
Wenn ich das richtig verstanden habe, haben MEINBIT15 und MEINBIT 42 
jeweils uint8_t. Dies haben in disem Beispiel den wert von 15 und 42. 
Bei 8 Bit können dise höchstens den Wert von 0-255 annnehmen.
Wenn ich beide Zahlen zusammen fassen möchte muss ich da nicht 
schreiben:
1
uint16_t reg16 |= 8<<MEINBIT15
damit verschienbe ich in reg16 (mit 16 Bit) MEINBIT15 um 8 Stellen nach 
links und kann anschliessend MEINBIT42 dazunehmen.
1
reg16 |= MEINBIT42
Damit habe ich jetzt in reg16 als höchstes Bit MEINBIT15 zu stehen und 
als tiefstes Bit MEINBIT42.
Im Beispiel gibt es auch reg_32. Ich kann als Beispiel auch 4 Zahlen mit 
8 Bit in reg_32 zusammen führen.
Versteh ich das richtig so?

von dummschwaetzer (Gast)


Lesenswert?

>uint16_t reg16 |= 8<<MEINBIT15
ist zu groß für 16Bit
du hast nur 16 Stellen. Wenn du die 8(binär 1000) 15 stellen nach links 
schiebst purzelt sie links raus

von Einer K. (Gast)


Lesenswert?

Karl schrieb:
> Wenn ich das richtig verstanden habe, haben MEINBIT15 und MEINBIT 42
> jeweils uint8_t.

Nein!
Das Zauberwort heißt "Integer Promotion". Der resultierende Datentype 
ist also eher int, als uint_8

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Karl schrieb:
> haben MEINBIT15 und MEINBIT 42
> jeweils uint8_t.

Genaugenommen haben die erstmal garkleinen type.
Der Preprocessor macht da eine einfache Textersetzung und erst beim 
späteren Compilieren wird dann was konkretes daraus:

z.B.: aus "reg_64 |= (1LL << MEINBIT42);" wird "reg_64 |= (1LL << 42);" 
usw.

von dummschwaetzer (Gast)


Lesenswert?

>#define MEINBIT15 15
>#define MEINBIT42 42
dise defines solltest du nur in Verbindung mit
1<<MEINBITyx
verwenden.
>reg16 |= MEINBIT42
macht garantiert nicht das wass du denkst.

von Georg M. (g_m)


Lesenswert?

Karl schrieb:
> Versuche gerade das Thema Bitmanipulation durchzuarbeiten und zu
> verstehen.

https://en.wikipedia.org/wiki/Bitwise_operations_in_C

von Karl (Gast)


Lesenswert?

Im Moment bringt ihr mich ganz schön durcheinander.

uint32_t reg_16 = ((MEINBIT15 << 8) | MEINBIT42);

Habe noch mal alles (versucht) zu lesen. Hab da wohl was verwechselt.
Sieht das besser aus und funktioniert so?

von Einer K. (Gast)


Lesenswert?

Karl schrieb:
> uint32_t reg_16 =

Diese Variablendefinition sieht sehr komisch aus....

von Karl (Gast)


Lesenswert?

Hab es einfach aus dem AVR GCC ... übernommen.
Soll eine uint mit 32 Bit (reicht auch 16 Bit) und 2 x 8 Bit Variablen 
sein.
Der Name ist eigentlich egal

von Philipp K. (philipp_k59)


Lesenswert?

Teste das doch in einem c online compiler mit Ausgabe in printf als 
binär.

Ein Mausklick und du hast unten gleich das Ergebnis.

: Bearbeitet durch User
von dummschwaetzer (Gast)


Lesenswert?

MEINBIT15 ist 15(dezimal), 1111 binär. F (hex)
wenn du jetzt
MEINBIT15 << 8 machst
erhälst du
1111 0000 0000 binär.
Ich glaube du verwechselst hier Grundlegende Schreibweisen.
Eine (in der AVR-Welt) gebräuchliche Darstellung ist diese 1<<Anzahl 
_Stellen
In einer anderen Welt nutzt man da ehr 0x8000 für Bit 15.
Tip:
Scheib dir die Zahlen erst mal binär hin.
Die Operation << schiebt die linke Seite um rechte Seite Stellen nach 
links.
Aus deiner 1<<MEINBIT15 wird also:
0000 0000 0000 0001(die eins)
1000 0000 0000 0000(15 mal nach links)
deine_Variable |= 1<<MEINBIT15
bewirkt, das das 15Bit gesetzt, alle anderen unverändert sind:
1xxx xxxx xxxx xxxx

von dummschwaetzer (Gast)


Lesenswert?

uint32_t reg_16 = ((MEINBIT15 << 8) | MEINBIT42);
(MEINBIT15 << 8) ist 1111 0000 0000 binär
MEINBIT42 ist 0010 1010 binär

reg_16 ist dann also 0000 0000 0000 0000 0000 1111 0010 1010 binär.
Gewollt hattest du aber Warscheinlich Bit 42 und Bit 15 gesetzt.
Geht nicht, weil dein reg_16 nur 32 Bit hat.

von Daniel S. (supernova01)


Lesenswert?

Hallo Karl,
1)
#define MEINBIT 32
ist nur ein define, das ist ein eigenes Thema, und verwirrt hier nur. Du 
müsstest erstmal verstehen was ein Define ist. Hier egal.

2)
Ebenso ungünstg für einen Einstig ist diese Kurzschreibweise:

reg |= x;

Auch unleserlich und verwirrend, dort steht eigentlich:

reg = reg | x;

3)Dann gleich alles zusammen mischen, verwirrt noch mehr, erstmal 
langsam anfangen

uint8_t a=0, b=1;

a=b<<3;

In b steht 0000 0001
In a danach 0000 1000

VG
Dennis

von Philipp K. (philipp_k59)


Lesenswert?

Karl schrieb:
> Sieht das besser aus und funktioniert so?

https://onlinegdb.com/qfdt59zV7

von Einer K. (Gast)


Lesenswert?

Karl schrieb:
> Der Name ist eigentlich egal

Nein!
Ist er nicht.

Deine Namensgebung ist an der Stelle verwirrend. Somit macht es das 
Quelltext Verständnis schwieriger. Dieser Thread soll allerdings dein 
Verständnis "schärfen", darum ist jede Art von Verwirrung 
kontraproduktiv.

Sorgfalt und Disziplin mindern Verwirrungen!

Lesetipp: "Clean Code"

Beitrag #6732964 wurde vom Autor gelöscht.
von (prx) A. K. (prx)


Lesenswert?

Regel fürs Verständnis, und typisches Missverständnis: Bei
  a = b <op> c
ist der Typ von a für die Auswertung von b<op>c völlig irrelevant. Erst 
das Resultat davon wird in den Typ von a konvertiert.

Somit wird 1<<15 als "int" ausgewertet, und liefert bei einer 16-Bit 
Kiste ein gesetztes Vorzeichenbit, also negativ. Die gleiche Operation 
bei einer 32-Bit Kiste liefert ein positives Ergebnis.

: Bearbeitet durch User
von Karl (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Lesetipp: "Clean Code"

#define MEINBIT15 15
#define MEINBIT42 42
main ()
{
uint32_t reg_32 = ((MEINBIT15 << 8) | MEINBIT42);
....
}
Das ist das gleich wie in der Quelle ich ich hatte.
Dabei wird in der Variable reg32 mit 32 Bit die Variable MEINBIT15 nach 
linls verschoben um 8 Stellen (MSB Stelle 15 bis 8), danach wird 
MEINBIT42 auf die Stelle LSB Stelle 7 bis 0 gesetzt.

(prx) A. K. schrieb:
> Eherne Regel fürs Verständnis: Bei
>   a = b <op> c
> ist der Typ von a für die Auswertung von b<op>c völlig irrelevant. Erst
> das Resultat davon wird in den Typ von a konvertiert.
>
> Somit wird 1<<15 als "int" ausgewertet, und liefert bei einer 16-Bit
> Kiste ein gesetztes Vorzeichenbit, also negativ. Die gleiche Operation
> bei einer 32-Bit Kiste liefert ein positives Ergebnis.

Sorry, das versteh ich nicht.

von (prx) A. K. (prx)


Lesenswert?

Karl schrieb:
>> Eherne Regel fürs Verständnis: Bei
>>   a = b <op> c
>> ist der Typ von a für die Auswertung von b<op>c völlig irrelevant. Erst
>> das Resultat davon wird in den Typ von a konvertiert.
>>
>> Somit wird 1<<15 als "int" ausgewertet, und liefert bei einer 16-Bit
>> Kiste ein gesetztes Vorzeichenbit, also negativ. Die gleiche Operation
>> bei einer 32-Bit Kiste liefert ein positives Ergebnis.
>
> Sorry, das versteh ich nicht.

Es geht z.B. um

> reg_32 |= (1 << MEINBIT15);

a = reg_32  # ist vom Typ uint32_t
b = 1       # ist vom Typ int
c = 15      # ist vom Typ int

Gerechnet wird also zuerst 1<<15 als int<<int, und das ergibt bei einer 
8/16-Bit CPU -32768. Das wird danach in 32-Bit konvertiert und behält 
dabei diesen Wert.

Verbreitetes Missverständnis bei Anfängern: Sie gehen fälschlicherweise 
davon aus, dass sich aus dem Typ von reg_32 die Breite der gesamten 
Rechnung ergibt.

von dummschwaetzer (Gast)


Lesenswert?

> Somit wird 1<<15 als "int" ausgewertet, und liefert bei einer 16-Bit
> Kiste ein gesetztes Vorzeichenbit, also negativ. Die gleiche Operation
> bei einer 32-Bit Kiste liefert ein positives Ergebnis.
16_Bit_signed: 0x8000
Erweitert auf 32Bit: 0xFFFF 8000 (das Vorzeichenbit wird in alle 
Höherwetigen Bits kopiert)

16_Bit_unsigned: 0x8000
Erweitert auf 32Bit: 0x0000 8000

von (prx) A. K. (prx)


Lesenswert?

Arduino Fanboy D. schrieb:
> Karl schrieb:
>> Wenn ich das richtig verstanden habe, haben MEINBIT15 und MEINBIT 42
>> jeweils uint8_t.
>
> Nein!

Soweit hast du recht.

> Das Zauberwort heißt "Integer Promotion". Der resultierende Datentype
> ist also eher int, als uint_8

Der Grund ist nicht Integer Promotion, sondern die Typermittlung 
lexikalischer Integer-Konstanten. Und da ist eine 1 per Sprachdefinition 
vom Typ "int". Eine Schreibweise für einfach hingeschriebene ganzzahlige 
Konstanten kleiner als "int" gibts nicht.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Karl schrieb:
> Sorry, das versteh ich nicht.

Das sind aber C und C++ Grundlagen.
Lese bitte das Kapitel über numerische Literale, integer Promotion und 
über die Wirkung der Operatoren. Zudem das Kapitel über implizite Casts, 
welche auch bei Zuweisungen zu tragen kommen.

(prx) A. K. schrieb:
> Der Grund ist nicht Integer Promotion, sondern die Typermittlung
> lexikalischer Integer-Konstanten.
Von mir aus...

von Philipp K. (philipp_k59)


Lesenswert?

Vielleicht einfacher:

int MEINWERT=15 //00000000000001111
15 bleibt 15

int MEINBIT = (int) (1<<15) //01000000000000000
Ist 32768

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Philipp K. schrieb:
> int MEINBIT = (int) (1<<15) //01000000000000000
> Ist 32768

Oder -32768. Je nach Plattform.

von Sebastian (Gast)


Lesenswert?

Karl schrieb:
> #define MEINBIT15 15
> #define MEINBIT42 42
> main ()
> {
> uint32_t reg_32 = ((MEINBIT15 << 8) | MEINBIT42);
> ....
> }

Du rechnest (15<<8)|42. Interessant, und ergibt 3882, hat ber nichts mit 
Bit Nummer 15 und auch nichts mit Bit Nummer 42 zu tun ...

LG, Sebastian

von Karl (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Verbreitetes Missverständnis bei Anfängern: Sie gehen fälschlicherweise
> davon aus, dass sich aus dem Typ von reg_32 die Breite der gesamten
> Rechnung ergibt.

Die Variable reg_32 hat eine Grösse von 32 Bit. Dabei steht in der MSB 
die Zahl 15 und in der LSB die Zahl 42.
Kann ich diese Zahlen auch wieder zurückholen?

von Sebastian (Gast)


Lesenswert?

Karl schrieb:
> Kann ich diese Zahlen auch wieder zurückholen?

Klar. reg_16>>8 gibt das obere Byte, reg_16&0xFF das untere.

LG, Sebastian

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.