Forum: Compiler & IDEs Shift-Problem?


von Martin (Gast)


Lesenswert?

Hallo zusammen,

ich bin blutiger Anfänger, also bitte um Nachsicht ;-)

In einem Programm möchte ich warten, bis auf PIND die letzten drei Bits 
1 sind. Meine Frage:

Warum tut es so:
1
while(~PIND & 0b00000111){warte();}

aber nicht so:
1
while((PIND << 5) != 0b11100000){warte();}

Die obere Bedingung wird false, wenn alle drei Bits 1 sind, wie 
gewünscht. Die untere Bedingung wird aber nie false, also die 
while-Schleife nie verlassen.

Danke schonmal,
Martin

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


Lesenswert?

Ich würde auf ein Vorzeichenproblem tippen.  Durch die Schiebeoperation
wird der Typ des entsprechenden Ausdrucks nach `int' promoted, und
sobald dann das Bit 7 gesetzt ist, werden die Bits 8...15 auch
gesetzt.

Probiere mal, ob das sich ändert, wenn du explizit mit "5U" schiebst
statt "5".

von Martin (Gast)


Lesenswert?

War mir gar nicht klar, dass der uint8 dann zum int wird. Das führt mein 
Shiften natürlich ad absurdum.

5U hat leider den gleichen Effekt.

von Stefan E. (sternst)


Lesenswert?

Ich würde sagen, dass das ein Compilerfehler ist, der optimiert hier 
etwas zu clever. Der Code sieht nämlich so aus:
1
+0000002F:   C001        RJMP    PC+0x0002        Relative jump
2
+00000030:   D006        RCALL   PC+0x0007        Relative call subroutine
3
+00000031:   B380        IN      R24,0x10         In from I/O location
4
+00000032:   3087        CPI     R24,0x07         Compare with immediate
5
+00000033:   F7E1        BRNE    PC-0x03          Branch if not equal

von Martin (Gast)


Lesenswert?

Kann ich so einen Codeabschnitt irgendwie als volatile o.ä. markieren, 
damit er nicht kaputtoptimiert wird?

von Der A. (der-albi)


Lesenswert?

Hallo.
Es gibt auch noch einen interessanten Unterschied: In der ersten Version 
überprüfst du mit Bitoperatoren, ob die unteren 3 Bit gesetzt sind. Das 
ist ok. Die Anderen Bits von PINx spielen dadurch keine rolle.

Bei der unteren Variante, vergleichst du logisch. Dabei zählen alle 
Bits.
Soweit ich weiß, arbeitet der Compiler bei so einem Vergleich mit ganzen 
ints. Also in dem fall 16bit. Das Shift5 löscht somit die anderen bits 
nicht.
Sie werden einfach ins HighByte verschoben. Dein 8bit Konstanten 
ausdruck ist auch ein int. sein HighByte ist 0.
Somit spielen die anderen Bits von PINx plötzlich eine Rolle.
Ich vermute das alles nur ;-) Bitte nicht lachen ;-)
Bei dem gezeigtes ASM weiß ich leider nicht, welche Version das ist. 
vermutlich die untere.. das all mein gebrabbel widerlegen würde :-D

Ich würde es nochmal mit:

while((unsigned char)(((unsigned char)PIND) << 5) != (unsigned 
char)0b11100000){warte();}
probieren. Das ist Nummer sicher ;-)

oder:

while(((PIND&0x07) << 5) != 0b11100000){warte();}

So.
MFG

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


Lesenswert?

Ich bin nach etwas Überlegung zur gleichen Erkenntnis gekommen.

von Martin (Gast)


Lesenswert?

Ich kann die Erklärung von Der Albi und Jörg (promotet zu was mit 16bit) 
bestätigen. Habe es jetzt (fast) wie von Der Albi vorgeschlagen:
1
while(( (PIND & 0b00000111) << 5) != 0b11100000){...}

Klappt wunderbar.

Danke Leute!

von Stefan E. (sternst)


Lesenswert?

Argh, ich konnte diese Integer-Promotions noch nie leiden.

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.