Forum: Compiler & IDEs shift unsigned int und shift 0x1 unterschiedlich


von Fred F. (alphateilchen)


Lesenswert?

Hallo,
ich bin vor einer Weile mal auf ein für mich seltsames Verhalten
Heute habe ich mal kurz mit eclipse und mingw ein kleines testprojekt 
gezimmert das mich noch mehr verwirrt.
Unten folgt gleich der Code. Kann mir jemand erklären (oder links zu 
Specs geben) warum der shift einer variablen die 0x1 enthält, mehr oder 
weniger in einem "rotate" endet und das shiften von 0x1 direkt mit 
Zuweisung das Ergebnis 0 ergibt?(jeweils shift um mehr als die 
Datentyplänge)

Bei einem ARM7 wird in keinem der Fälle rotiert sondern die 
"rausgeschifteten" Bits werden verworfen. (mit TI compiler)

Ich weis daß es rund um das shiften bei den C Standards diverse 
"implementation defined" und "undefined" Behaviour gibt.
Ich wüsste nur gerne etwas genauer warum das unten im code scheinbar so 
uneinheitlich ist. Ich würde verstehen wenn dann generell rundum 
geschiftet wird, aber warum einmal "0" und einmal "0x8" draus wird 
verstehe ich nicht.
Ist das dadurch bedingt daß im einen Fall ein Befehl mit "imidiate 
operand" verwendet wird, wobei bei Intel immer die shiftweite per Maske 
begrenzt wird, oder ist das eine GCC Eigenheit?
Soweit ich mich erinnere verhällt sich das Visual Studio aber ähnlich.

Ich habe bisher keine Erfahrung mit eclipse daher weis ich nicht wie man 
source und assembler in einer Art mixed View wie beim Texasinstrument 
CCStudio einblendet, sonst hätte ich vieleicht schon etwas mehr 
Informationen.

Die jeweils als Kommentar angegebenen Werte stammen aus dem watch 
Fenster.

int main(void)
{
  unsigned int  ui;

  ui   = 0x1;//0x1
  ui <<= 35; //0x8 => shiftet im kreis

  ui   = 0x1;//0x1
  ui   = ui << 35;//0x8 => shiftet im kreis

  ui = 1uL<<35;//0x0  !!!!
  ui = 0x1<<35;//0x0  !!!!
...
}

Danke für Eure Hilfe

von yalu (Gast)


Lesenswert?

Ohne mich mit dem Befehlssatz des Pentium genauer auszukennen, würde ich
vermuten, dass der Prozessor vom rechten Operand der Shift-Operation nur
die untersten 5 Bits berücksichtigt. Der Ausdruck

  a << b

wird also vom Prozessor wie

  a << (b & 0x1f)

ausgeführt. Ein Links-Shift um 35 Bits führt somit zu einem Links-Shift
um 3 Bits. Das Ergebnis hat den Anschein, als ob der erste Operand
rotiert worden wäre, in Wirklichkeit wird er nur um einen um 32 zu
kleinen Wert geshiftet.

In den beiden letzten Beispielen sind beide Operanden des Shifts
konstant, so dass der Ausdruck bereits zur Compilezeit berechnet wird.
Offensichtlich verwendet der Compiler eine andere Rechenroutine
(vielleicht mit 64-Bit-Arithmetik oder mit einer Schleife), so dass eine
0 herauskommt.

Wenn du die Optimierung aktivierst, werden auch die ersten beiden
Ausdrücke bereits zur Compilezeit berechnet, so dass auch dort das
Ergebnis 0 ist.

Da In C Shifts undefiniert sind, wenn die Shiftlänge >= der
Datentypbreite ist, ist dieses Verhalten aber völlig in Ordnung.

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.