Bits schieben

Gast #1859082
Lesenswert?
• ▲
▼
Ich wollte die (invertierten) Portleitungen D7~4 abfragen.
Ergebnis sollte eine Zahl von 0 bis 15 sein.
1
unsigned char n;
2
n = (~PIND) >> 4;
Zuerst wird doch PIND invertiert.
Dann wird das Ergebniss viermal rechtsgeschoben.
Da n unsigned char ist, sollten doch links nullen nachgeschoben werden?!
Leider klappt das so nicht.
1
unsigned char n;
2
n = ((~PIND) >> 4) & 0b00001111;
Aber so klappt es. Warum ist die maskierung mit 0b00001111 nötig?
Moderator Persönliche Seite #1859121
Lesenswert?
• ▲
▼
Heiopei schrieb:

> Da n unsigned char ist, sollten doch links nullen nachgeschoben werden?!

Diese Begründung ist nicht richtig. Mit n hat das nix zu tun, da n gar 
nicht geschoben wird.

Jetzt fragt sich, ob der Kompiler aus den 8Bit bei der Komplementierung 
von PIND einen Integer macht. Der wäre auf dem AVR 16 bit breit. Dann 
wird bei

   PIND = 0b01010101

das Ergebnis von ~PIND auf 16 Bit aufgebohrt, also:

   ~PIND : 0b1111111110101010

Wenn man das nach rechts schiebt um 4 Stellen, dann wird daraus:

   (~PIND) >> 4: 0b1111111111111010

Oben schieben sich bei negativen Zahlen (2er Komplement) 1en rein[1], 
spielt hier aber keine Rolle, denn es werden nur die untersten 8 Bit im 
n gespeichert. Dann sieht n so aus:

   n: 0b11111010

Wohlgemerkt, alles nur, wenn der Compiler das Ergebnis von ~PIND auf 16 
Bit (= Integer auf z.B. ATmega8) aufbohrt. Um welchen Compiler/Prozessor 
handelt es sich denn?

Gruß,

Frank

[1] Vielleicht wird aus ~PIND auch ein unsigned int, dann kommen halt 4 
0en von oben rein. Nützt Dir aber auch nix. Du hast immer noch 4 Einsen 
vor Deinem Wert.
Moderator Persönliche Seite #1859127
Lesenswert?
• ▲
▼
Klaus Wachtler schrieb:
> Überrascht mich jetzt spontan auch.
> Offenbar ist ~PIND erstmal wieder signed.

Ob signed oder nicht, ist egal, ~PIND es ist halt ein Integer mit 16 
Bit. Kann auch unsigned int sein, Du hast trotzdem 8 Einsen im 
höherwertigen Byte. Die kriegst Du durch Shiften um 4 Stellen auch nicht 
weg ;-)

> Die Lösung ist:
>
1
> n = ( (unsigned char /* bzw. uint8_t */)(~PIND) >> 4) & 0b00001111;
2
>

Jepp. Hier verkleinerst Du (~PIND) wieder auf 8 Bit. Damit ist wieder 
alles im Lot und das "& 0b00001111" kann man sich wieder sparen.

Gruß,

Frank
Gast #1859166
Lesenswert?
• ▲
▼
vielen Dank für die rege Anteilnahme

Frank M. schrieb:
> Um welchen Compiler/Prozessor handelt es sich denn?

Der Compiler ist der GCC vom AVR Studio 4.
Der Proz ist der ATmega8.

In der Datei IOM8.h steht:
#define PIND  _SFR_IO8(0x10)

Nun ist mir immer noch nicht klar, wie der Compiler darauf kommt,
das Ergebnis von ~PIND auf 16 Bit aufgebohren.
Klar, das maskieren mit 0b00001111 oder casting auf unsigned char hilft, 
ist aber irgendwie nur ein kurieren der Sympthome...   ;-)
#1859177
Lesenswert?
• ▲
▼
Stichwort: Integer promotion.  Die gilt auch für den ~-Operator.  Sie 
besagt (vereinfacht), dass alle Berechnungen mindestens in int 
durchzuführen sind und für kleinere Typen vor der Anwendung des 
Operators zunächst die Variablen nach int aufgeblasen werden müssen.

Der Compiler berechnet also zu Recht das Komplement von 0x00n0 anstelle 
von 0xn0.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.