Forum: PC-Programmierung [C] Problem mit Rechtsschieben


von B. S. (bestucki)


Lesenswert?

Hallo zusammen,

Entweder bin ich blind, zu blöd oder mein Compiler verarscht mich.


Dieses Minimalbeispiel
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdint.h>
4
5
int main(int argc, char *argv[])
6
{
7
  uint8_t i;
8
  uint8_t value=0x8F;
9
  uint8_t shift=40;
10
11
  for(i=0;i<shift;i++){
12
    printf("%u",(value>>(shift-i-1))&1);
13
  }
14
15
  getch();
16
  return 0;
17
}
erzeugt mir folgenden Output:
1
1000'1111'0000'0000'0000'0000'0000'0000'1000'1111
(Die Apostroph habe ich manuell eingefügt, damit mans besser lesen kann)


Warum rotiert mein Compiler die Variable value? Es sollten doch von 
links immer nur Nullen nachgeschoben werden, egal wie weit ich schiebe. 
Hab ich irgendwas verpasst oder stimmt hier was nicht?

Sprache: C
Compiler: DEV C++ V4.9.9.2, C-Projekt erstellt, Ohne Optimierung

von michael (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich hab das grad mal im Visual Studio probiert. Gleiches Ergebnis. Warum 
kann ich dir leider auch nicht sagen.
Beim ersten Durchlauf der Schleife ist i=0, value müsste also um 39 
Stellen nach rechts geschoben werden. Das Ergebnis müsste 0 sein.
Bin da auch ratlos.

Viele Grüße
Michael

von g457 (Gast)


Lesenswert?

> egal wie weit ich schiebe

Nein, nur bis 32.

von Kaj (Gast)


Lesenswert?

[c]value>>(shift-i-1))&1[/]
annahmen:
value = 0x8F
shift = 40
i = 0

Du nimmst den Wert 0x8F und schiebst ihn um 39 Stellen (40-0-1) nach 
rechts und verundest ihn mit 1....

Frage: wie viele Bit-Stellen hat so ein uint8_t?

Deine Schleife läuft zu lange und damit verlässt du gewisse grenzen.

Und wenn du dir dein Ergebnis mal genau anschauen würdest, würdest du 
sehen, das
> Es sollten doch von
> links immer nur Nullen nachgeschoben werden
auch stimmt, aber nur für die ersten 32 bit, danach fängt es wieder von 
vorne an.

von michael (Gast)


Angehängte Dateien:

Lesenswert?

Aus C99:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has 
an unsigned type or if E1 has a signed type and a nonnegative value, the 
value of the result is the integral part of the quotient of E1 / 2^E2. 
If E1 has a signed type and a negative value, the resulting value is 
implementation-defined.

http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
$6.5.7

Eigentlich dürfte da ab Zeile 8 nur noch 0 stehen.

???

Ich geh jetzt schlafen.
Vielleicht hat ja morgen jemand eine Lösung.
Gute Nacht.

von B. S. (bestucki)


Lesenswert?

Vielen Dank für die Antworten, habs jetzt auch im Reference Manual von 
K&R (2. Auflage, Kapitel A7.8) gefunden:
> The result is undefined if the right oparand is negative, or greater
> than or equal to the number of bits in the left expression's type.

Da hätte ich mir einige Stunden Fehlersuche sparen können. Aber wer 
schaut schon im Reference Manual nach...

Edit: War zu langsam

von g457 (Gast)


Lesenswert?

1
The integer promotions are performed on each of the operands. The type of the result is
2
that of the promoted left operand. If the value of the right operand is negative or is
3
greater than or equal to the width of the promoted left operand, the behavior is undefined.

Ebenfalls $6.5.7.

Guds Nächdle

von Karl H. (kbuchegg)


Lesenswert?

Wenn du um mehr Bits schiebst als der zu schiebende Datentyp überhaupt 
groß ist, ist das Ergebnis undefiniert. Damit gibt es dann kein 
'richtig' oder 'falsch' mehr.

von michael (Gast)


Lesenswert?

g457 schrieb:
> The integer promotions are performed on each of the operands. The type
> of the result is
> that of the promoted left operand. If the value of the right operand is
> negative or is
> greater than or equal to the width of the promoted left operand, the
> behavior is undefined.

oh verdammt, hab ich glatt überlesen

von B. S. (bestucki)


Lesenswert?

Kaj schrieb:
> Frage: wie viele Bit-Stellen hat so ein uint8_t?
8 natürlich :)

> Deine Schleife läuft zu lange und damit verlässt du gewisse grenzen.
Ich habe bis jetzt gedacht, dass ich schieben kann wie ein Bekloppter 
und da immer Nullen nachgeschoben werden. Leider nein... Baue ich halt 
eine Prüfung in mein Programm ein.

Kaj schrieb:
> auch stimmt, aber nur für die ersten 32 bit, danach fängt es wieder von
> vorne an.
Das hab ich dann auch bemerkt.


Vielen Dank für eure Hilfe!

von Uhu U. (uhu)


Lesenswert?

Wenn man das Programm auf einem 32-Bit-80x86-Rechner ausführt und der 
Compiler für die Shiftoperation den Hardware-Shift einsetzt - was 
wahrscheinlich ist - passiert folgendes:

Der Shiftwert wird mod 32 genommen und das Register um soviel Bit nach 
rechts geschoben.

Für die Shiftwerte 39..32 wird also der Operand um 7..0 Bit geschoben - 
das Resultat sind die links stehenden 1000'1111 - Bits

Unterschreitet der Schiftwert 32, dann wird der Operand um diese Zahl 
bits geschoben - daraus resultieren die folgenden 3 0000'0000-Bytes

Erst wenn der Shiftwert < 7 geworden ist, bleibt vom Operanden ein Wert 
!= 0 - das ist das 1000'1111-Byte ganz rechts.

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.