www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik shiften funktioniert nicht


Autor: sam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
folgendes funktioniert bei mir nicht:

unsigend long a;
unsigend long b;

b = (a<<16);

was ist hier falsch...
gruss samy

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Woher weist du das es nicht geht ?
Was passiert denn ?

Autor: Rolf Magnus (Gast)
Datum:

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

a ist nicht initialisiert.

Autor: Thomas Stütz (tstuetz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.