Forum: Mikrocontroller und Digitale Elektronik shiften funktioniert nicht


von sam (Gast)


Lesenswert?

Hallo,
folgendes funktioniert bei mir nicht:

unsigend long a;
unsigend long b;

b = (a<<16);

was ist hier falsch...
gruss samy

von Benedikt (Gast)


Lesenswert?

Woher weist du das es nicht geht ?
Was passiert denn ?

von Rolf Magnus (Gast)


Lesenswert?

> unsigend long a;
> unsigend long b;
>
> b = (a<<16);
>
> was ist hier falsch...

a ist nicht initialisiert.

von Thomas S. (tstuetz)


Lesenswert?

"unsigend long a;
unsigend long b;"

heißt das nicht "unsigned long" ?
Außerdem mach mal hinter dem 16 noch ein L ran "a = (b << 16L)"

Gruss

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das L als Suffix der Konstanten ist nicht erforderlich.
Das rechte Argument des Shift-Operators darf nie so groß werden wie die
Anzahl der Bits des linken Ausdrucks; wenn "long" eine 32-Bit-Variable
ist, darf maximal um 31 geshiftet werden. Wird mit 32 geshiftet, ist das
Ergebnis undefiniert.
(Ist so bei C und C++ definiert).

von Peter Dannegger (Gast)


Lesenswert?

@Rufus

"Das L als Suffix der Konstanten ist nicht erforderlich."

Nein.

Das L als Suffix der Konstanten ist immer dann erforderlich, wenn der
andere Operand nicht 32 Bit ist, aber das Ergebnis 32 Bit sein soll.


Die Rechnung wird immer in dem Format durchgeführt, welches dem
Operanden mit dem größeren Format entspricht.
Die Umwandlung ins Zielformat erfolgt erst hinterher:

unsigned long i = 16 << 16; // ergibt 0

unsigned long i = 16L << 16; // ergibt 0x100000L
unsigned long i = 16 << 16L; // ergibt 0x100000L
unsigned long i = 16L << 16L; // ergibt 0x100000L



"Wird mit 32 geshiftet, ist das Ergebnis undefiniert."

Seit wann denn das ?

Von unten werden Nullen reingeschoben, d.h. das Ergebnis ist immer 0.

Manche Programmierer benutzen sogar diesen Befehl, um ein Register zu
löschen.


Peter

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

.

   "Wird mit 32 geshiftet, ist das Ergebnis undefiniert."

   Seit wann denn das ?

Das steht so sowohl im ANSI-C- als auch im C++-Standard. Das von Dir
geschilderte Verhalten muss so nicht sein.

Hier das Verhalten, wie es beispielsweise der VC++ 6.0-Compiler von
Microsoft an den Tag legt:


183:          unsigned long bla;
184:
185:          bla = 1;
0040161C   mov         dword ptr [ebp-9Ch],1
186:
187:          bla <<= 32;
00401626   mov         eax,dword ptr [ebp-9Ch]
0040162C   shl         eax,20h
0040162F   mov         dword ptr [ebp-9Ch],eax

Das sieht alles ganz unverdächtig aus; betrachtet man aber den
Shift-Befehl (shl eax,20h) genauer und liest die Dokumentation, so
steht da (Zitat Borland Turbo Assembler-Referenzhandbuch)

  Um die maximale Ausführungszeit zu verringern, erlaubt der
  80286/80386-Prozessor nicht mehr als 31 Schiebe-Operationen.
  Werden mehr als 31 Schiebe-Operationen angegeben, so werden
  lediglich die unteren fünf Bits einbezogen.

Die unteren 5 Bits von 0x20 sind 0. Das Resultat obigen Codefragments
ist also 1.

OK, so nimmt man zuerst an, daß MS hier (noch) einen schweren
Compilerfehler programmiert hat, so findet man nach einiger Suche das
hier:

  5.8 - Shift operators [expr.shift]

  -1- The shift operators << and >> group left-to-right.

  shift-expression:
  additive-expression
  shift-expression << additive-expression
  shift-expression >> additive-expression

  The operands shall be of integral or enumeration type and
  integral promotions are performed. The type of the result
  is that of the promoted left operand.
  The behavior is undefined if the right operand is negative,
  or greater than or equal to the length in bits of the
  promoted left operand.

  (Quelle: ISO/IEC 14882:1998)


Der letzte Satz ist entscheidend.

von Peter Dannegger (Gast)


Lesenswert?

Jetzt, wo Du es sagst, erinnere ich mich wieder:

Beim 8086 wurde SHL mit 255 gerne als Delayloop verwendet, mit der
Folge, daß aufm 80286 alles viel zu schnell ablief. Und obendrein war
das Register nicht mal richtig gelöscht.


D.h. also, wenn Werte größer als 31 auftreten können, muß man das
abtesten und getrennt behandeln.


Peter

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Naja, das betrifft alle Datentypen.

  uint8_t darf maximal mit 7 geshiftet werden,
  uint16_t maximal mit 15
  uint32_t maximal mit 31
  uint64_t maximal mit 63

Das ist äußerst heimtückisch.

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.