Bitmanipulation

Gast #6732854
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?
Gast #6732919
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?
Gast #6732947
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
Gast #6732954
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.
#6732955
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
Gast #6732962
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 von einem Moderator gelöscht.
#6732972
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.
Gast #6732980
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.
#6732988
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.
Gast #6732990
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
#6732994
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.
Gast #6732996
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...
Gast #6733027
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
Gast #6733029
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?

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