Schiebeoperatoren

#2165292
Lesenswert?

Hallo zusammen.
Ich wollte mir ein Lauflicht programmieren, was von links nach rechts 
und von rechts nach links läuft. Allerdings bin ich auf ein etwas 
merkwürdiges Problem gestoßen.

Mein Lauflicht soll am Port 0 ausgegeben werden. Für das Lauflicht von 
rechts nach links sieht das ganze dann so aus:
1
  {   
2
    x=0x01;
3

4
    for(z=1;z<9;z++)
5
    {
6
      P0=x;
7
      x=x<<1;
8
      init();        // Timer für Pause aufrufen
9
    }
10
  }

Das funktioniert soweit auch noch einwandfrei.
Dann müsste das ganze von links nach rechts ja wie folgt aussehen:
1
  {  
2
    x=0x80;
3

4
    for(z=1;z<9;z++)
5
    {
6
      P0=x;
7
      x=x>>1;
8
      init();        // Timer für Pause aufrufen
9
    }
10
  }

Komischer Weise funktioniert dies aber nicht. Die "1" wird zwar um eine 
Stelle nach rechts weitergeschoben, aber die vorherige Stelle wird nicht 
mehr mit einer 0 aufgefüllt, sondern bleibt 1 . Ich habe also eine 
"auffüllendes Licht", sodass am Ende alle LED's an sind.

Kann mir jemand vielleicht sagen wo mein Fehler ist ?

MfG
#2165313
Lesenswert?

Ich bin zwar nicht "du:", aber:

Bei vorzeichenbehafteten Zahlen ist das höchste Bit gesetzt, wenn
die Zahl negativ ist.

Beispiel int8_t:
1
 dezimal  heaxdezimal  binär
2
    127   0x7F         01111111
3
    126   0x7E         01111110
4
    125   0x7D         01111101
5
     ...
6

7
    2     0x02         00000010
8
    1     0x01         00000001
9
    0     0x00         00000000
10
   -1     0xFF         11111111
11
   -2     0xFE         11111110
12
   -3     0xFD         11111101
13
    ...
14
   -126   0x82         10000010
15
   -127   0x81         10000001
16
   -128   0x80         10000000

Würde eine negative Zahl (gesetztes oberstes Bit einfach nur nach
rechts geschoben und eine 0 links eingefügt, dann würde sie dadurch
ja positiv werden (oberstes Bit jetzt 0).
Das ist nicht erwünscht, weil man das Rechtsschieben auch gerne als
schnelle Division durch 2 nimmt.

Deshalb wird eine 1 statt der 0 links eingefügt.

(Analog bei größeren Typen.)

Das heißt auch "arithmetisches Shiften".

Bei unsigned ist dagegen das oberste ja kein Vorzeichenbit,
also entfällt diese Begründung und es wird mit Nullen aufgefüllt.
Moderator #2165332
Lesenswert?

Eigentlich ist der Rechts-Shift einer negativen Zahl im C-Standard gar
nicht genau festgelegt, er ist "implementation-defined". Möchte man
portablen Code schreiben, sollte man nur positve Zahlen nach rechts
schieben.

Die meisten C-Compiler übersetzen x>>n in eine ASR-Instruktion
(arithmetic shift right) des Prozessors, wenn x vorzeichenbehaftet ist,
und in eine LSR-Instruktion (logic shift right), wenn x vorzeichenlos,
also unsigned ist. Das ergibt dann das von Klaus beschriebene Verhalten.
#2165986
Lesenswert?

...ein weiterer Ansatz für ein Lauflicht wäre:

Nimm eine Zählvariable (von 0-255) und ordne jedem Pin 2 Defines zu 
(pinXan und pinXaus). Bei jedem Schleifendurchlauf könnte man gucken ob 
der jeweilige pin an oder aus sein soll indem man die Werte für die Pins 
jeweils in jedem Schleifendurchlauf entsprechend mit der Zählvariable 
vergleicht...

Für dein lauflicht Würde es dann so aussehen:

pin0an = 0
pin0aus = 31

pin1an = 32
pin1aus = 63

usw..

pin7an = 224
pin7aus = 255

Da man ja jedem Pin diese zeitliche "Position" zuordnen kann, kann man 
wirklich tolle effekte erreichen...

T.
Gast #2166963
Lesenswert?

A. K. schrieb:
> Die in Prozessoren oft vorhandene Rotation ohne Carry wäre in
> Verschlüsselungsfunktionen ganz praktisch, da die recht oft damit
> arbeiten.

Es gibt kein direktes C-Konstrukt dafür. Das heißt aber nicht, dass der 
Compiler das nicht verwendet.

Beispiel für den ARM:
1
#include <stdint.h>
2

3
uint32_t rotate_right(uint32_t x, unsigned int pos)
4
{
5
  x = (x >> pos) | (x << (32 - pos));
6
  return x;
7
}

Resultierender Code (gcc mit Optimierung -O2):
1
rotate.o:     file format elf32-littlearm
2

3

4
Disassembly of section .text:
5

6
00000000 <rotate_right>:
7
   0:  e1a00170   ror  r0, r0, r1
8
   4:  e12fff1e   bx  lr

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