C wie confusion...

  • C wie confusion...

    Hallo, bin wieder mal am verzweifeln. Kann mir jemand erklären wie der Unterschied im Resultat zustande kommt?

    Quellcode

    1. #include <stdio.h>
    2. int main(int argc, const char **argv) {
    3. int a, b, c;
    4. a = 0x1f;
    5. b = 1 << (a + 1);
    6. c = 1 << (0x1f + 1);
    7. printf("a: %d, b: %d, c: %d\n", a, b, c);
    8. return 0;
    9. }
    Alles anzeigen


    liefert

    Quellcode

    1. a: 31, b: 1, c: 0


    Danke.
    Gruss Dominik.
  • Ich hab kurz mit c# (Hab in der Firma kein C Compiler installiert) ausprobiert und es gibt in beiden Fällen das Gleich. Müsste eigentlich keinen Unterschied zu C machen, da der int auch 32 Bit ist.

    Ich vermute mal (reine Spekulation), dass der Kompiler probleme hat die 1 direkt zum hex Wert zu addieren und das einfach weglässt, somit wäre die 1 an der Stelle des Vorzeichens im int, was 0 gleichkäme.
    Ialea iacta est
  • Original von deconceptional
    Original von below

    Aber wir sollen hier doch nicht Deine Hausaufgaben lösen, oder doch?

    Alex


    Eigentlich schon :D Auch wenn sich das Problem nebenbei eingeschlichen hat und nicht wirklich teil der Aufgabe ist...


    Wusste ich es doch :p

    Das las sich so wie eine Übungsaufgabe...

    Alex
    The only thing that really worried me was the ether.
  • Gerade noch folgendes gesehen

    Aus der Übungsaufgabe
    You may assume that your machine:
    1. Uses 2s complement, 32-bit representations of integers.
    2. Performs right shifts arithmetically.
    3. Has unpredictable behavior when shifting an integer by more
    than the word size.


    Die Frage hat sich dann wohl erledigt... => Muss eine neue Lösung her :sick:
    Gruss Dominik.
  • Erstmal sind a, b, c als int definiert und damit 32-bit Werte.

    a ist 31.
    b: du schiebst die 1 um 32-bit nach oben raus, das Ergebnis sollte also 0 sein.
    c: du schiebst die 1 um 32-bit nach oben ruas, das Ergebnis ist dann auch 0.

    Woher jetzt der Unterschied?

    Der Compiler optimiert so manches einfach weg.
    Im Fall von c merkt der Compiler (nur konstante Ausdrücke), dass das eine Bit oben rausgeschoben wird und kompiliert dann einfach c = 0;
    Im Fall von b wird der Compiler aber tatsächlich die Shift-Operation generieren. Auf einem Intel-Mac wird daraus ein Shift um 32-bit. Die Intel-CPU (laut Intel-Dokumentation) maskiert den Shift-Count so, dass nur die unteren 5 bit übrig bleiben (aus Performanz-Gründen) - heraus kommt ein Shift um 0 bit - also wird das Ergebnis 1.
    Die PPC-Opcode (slw) akzeptiert auch nur 5 bit für den Shift-Count, ist das 6-Bit gesetzt ist das Ergebnis immer 0.

    Wenn Du also schreibst:

    Quellcode

    1. int a = 31;
    2. int b = 1 << a;
    3. b = b << 1;
    4. /* gibt es b <<= 1 ??? */
    sollte also auf jeden Fall 0 rauskommen...

    Im übrigen ist im C-Standard nicht definiert, was passiert, wenn man um mehr Bits shiftet, als die Architektur-Breite Bits hat.
  • Das ist allerdings erstaunlich! Und zwar das b!

    Ich gehe mal davon aus, dass du auf 32 Bit kompilierst. Dann hat ein int also 32 Bit. Dementsprechend ist ein
    1 << 32
    sinnfrei, da du die 1 komplett heraus schiebst. Das richtige Ergebnis wäre also eigentlich 0.

    Ich mutmaße aber mal, dass er vllt bei b irgendwie einen größeren Typen nimmt und das deshalb in den Griff bekommt.

    Die Warnung bei c) ist aus oben genannten Grund richtig.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von ssb
    Erstmal sind a, b, c als int definiert und damit 32-bit Werte.

    a ist 31.
    b: du schiebst die 1 um 32-bit nach oben raus, das Ergebnis sollte also 0 sein.
    c: du schiebst die 1 um 32-bit nach oben ruas, das Ergebnis ist dann auch 0.

    Woher jetzt der Unterschied?

    Der Compiler optimiert so manches einfach weg.
    Im Fall von c merkt der Compiler (nur konstante Ausdrücke), dass das eine Bit oben rausgeschoben wird und kompiliert dann einfach c = 0;
    Im Fall von b wird der Compiler aber tatsächlich die Shift-Operation generieren. Auf einem Intel-Mac wird daraus ein Shift um 32-bit. Die Intel-CPU (laut Intel-Dokumentation) maskiert den Shift-Count so, dass nur die unteren 5 bit übrig bleiben (aus Performanz-Gründen) - heraus kommt ein Shift um 0 bit - also wird das Ergebnis 1.
    Die PPC-Opcode (slw) akzeptiert auch nur 5 bit für den Shift-Count, ist das 6-Bit gesetzt ist das Ergebnis immer 0.

    GENIAL! Darauf muss man erst einmal kommen!
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Tom9811
    Original von ssb
    Erstmal sind a, b, c als int definiert und damit 32-bit Werte.

    a ist 31.
    b: du schiebst die 1 um 32-bit nach oben raus, das Ergebnis sollte also 0 sein.
    c: du schiebst die 1 um 32-bit nach oben ruas, das Ergebnis ist dann auch 0.

    Woher jetzt der Unterschied?

    Der Compiler optimiert so manches einfach weg.
    Im Fall von c merkt der Compiler (nur konstante Ausdrücke), dass das eine Bit oben rausgeschoben wird und kompiliert dann einfach c = 0;
    Im Fall von b wird der Compiler aber tatsächlich die Shift-Operation generieren. Auf einem Intel-Mac wird daraus ein Shift um 32-bit. Die Intel-CPU (laut Intel-Dokumentation) maskiert den Shift-Count so, dass nur die unteren 5 bit übrig bleiben (aus Performanz-Gründen) - heraus kommt ein Shift um 0 bit - also wird das Ergebnis 1.
    Die PPC-Opcode (slw) akzeptiert auch nur 5 bit für den Shift-Count, ist das 6-Bit gesetzt ist das Ergebnis immer 0.

    GENIAL! Darauf muss man erst einmal kommen!

    allerdings - da muss man drauf kommen.

    und meiner meinung nach ises eben falsch. wenn ich 256 in einen byte schreibe soll dort ja auch nicht 1 oder 2 sondern 0 stehen
  • Original von gritsch
    Original von Tom9811
    GENIAL! Darauf muss man erst einmal kommen!

    allerdings - da muss man drauf kommen.

    und meiner meinung nach ises eben falsch. wenn ich 256 in einen byte schreibe soll dort ja auch nicht 1 oder 2 sondern 0 stehen

    Was falsch ist, bestimmt der Standard. Und ssb hat bereits ausgeführt, dass das "Herausschieben" nicht definiert ist. Also ist es richtig, wenn da 35429 steht.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Wow, da fehlt tatsächlich ein shift 8o

    Quellcode

    1. .cstring
    2. LC0:
    3. .ascii "a: %d, b: %d, c: %d\12\0"
    4. .text
    5. .globl _main
    6. _main:
    7. pushl %ebp
    8. movl %esp, %ebp
    9. pushl %ebx
    10. subl $36, %esp
    11. call L3
    12. "L00000000001$pb":
    13. L3:
    14. popl %ebx
    15. movl $31, -20(%ebp)
    16. movl -20(%ebp), %ecx
    17. incl %ecx
    18. movl $1, %eax
    19. sall %cl, %eax
    20. movl %eax, -16(%ebp)
    21. movl $0, -12(%ebp)
    22. movl -12(%ebp), %eax
    23. movl %eax, 12(%esp)
    24. movl -16(%ebp), %eax
    25. movl %eax, 8(%esp)
    26. movl -20(%ebp), %eax
    27. movl %eax, 4(%esp)
    28. leal LC0-"L00000000001$pb"(%ebx), %eax
    29. movl %eax, (%esp)
    30. call L_printf$stub
    31. movl $0, %eax
    32. addl $36, %esp
    33. popl %ebx
    34. leave
    35. ret
    36. .section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
    37. L_printf$stub:
    38. .indirect_symbol _printf
    39. hlt ; hlt ; hlt ; hlt ; hlt
    40. .subsections_via_symbols
    Alles anzeigen
    Gruss Dominik.
  • Original von Tom9811
    Original von gritsch
    Original von Tom9811
    GENIAL! Darauf muss man erst einmal kommen!

    allerdings - da muss man drauf kommen.

    und meiner meinung nach ises eben falsch. wenn ich 256 in einen byte schreibe soll dort ja auch nicht 1 oder 2 sondern 0 stehen

    Was falsch ist, bestimmt der Standard. Und ssb hat bereits ausgeführt, dass das "Herausschieben" nicht definiert ist. Also ist es richtig, wenn da 35429 steht.


    ich sagte ja "nach meiner meinung" und nicht nach dem standard oder der definition ;)
  • Original von gritsch
    ich sagte ja "nach meiner meinung" und nicht nach dem standard oder der definition ;)

    Das ist aber deiner Meinung nach der Standard falsch. Ein Compiler, der sich an den Standard hält, macht per definitionem nichts falsch. Das ist ja der persönlichen Meinung nicht zugänglich.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von gritsch
    ich sagte ja "nach meiner meinung" und nicht nach dem standard oder der definition ;)

    In der Norm ist laufend von undefined behavior die Rede. Damit hat man es den Compiler Hersteller leichter gemacht. Es gab früher einige ganz wilde Architekturen, z.B. mit CHAR_BIT = 9. Daher stammen so einige der Altlasten in der ISO Norm.