Select Case True

  • VB.NET

Es gibt 35 Antworten in diesem Thema. Der letzte Beitrag () ist von JLH.

    Select Case True

    VB.NET-Quellcode

    1. ​Select Case True
    2. Case Checkbox1.Checked
    3. füge block1 ein
    4. Case Checkbox2.Checked
    5. füge block2 ein
    6. .
    7. .
    8. .
    9. .
    10. End Select


    Wenn in obigem Beispiel der erste Case erfüllt ist werden ja alle weiteren Cases nicht ausgewertet. Die könnten aber auch alle wahr sein. Mit If Then kriege ich das hin, aber gibt es eine elegantere Lösung so wie die Case Anweisung die trotz Erfüllung schaut ob noch mehr wahr sind?

    Thanks
    Dafür ist Select Case nicht ausgelegt. Die Übersetzung sollte da für Klarheit schaffen: Wähle Fall. Wenn mehrere Fälle zutreffen können, ist es einfach nicht sinnvoll, Select Case zu verwenden. In C# kann man das break im switch-Block weglassen, um das gewünschte Ergebnis zu erzielen. Aber sowas gibt es eben in VB.NET nicht. Daher ist m.E. If das richtige. Und zwar ohne Else-Zweige.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Auf vb-forums.com hatten sich schon mal einige dran versucht. Ergebnis: naja …
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @JLH Wenn alle Fälle unabhängig voneinander eintreten können, musst Du sie auch alle einzeln und unabhängig voneinanderabtesten,
    also für jeden einzelnen Fall ein If - End If.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Da fällt mir in C spontan Duff's Devices ein:

    C-Quellcode

    1. send(to, from, count)
    2. register short *to, *from;
    3. register count;
    4. {
    5. register n = (count + 7) / 8;
    6. switch (count % 8) {
    7. case 0: do { *to = *from++;
    8. case 7: *to = *from++;
    9. case 6: *to = *from++;
    10. case 5: *to = *from++;
    11. case 4: *to = *from++;
    12. case 3: *to = *from++;
    13. case 2: *to = *from++;
    14. case 1: *to = *from++;
    15. } while (--n > 0);
    16. }
    17. }


    Aber in modernen Hochsprachen machen solche Konstrukte keinen Sinn, weshalb man auch nicht mehr durchfallen kann.

    Was du natürlich machen kannst, ist alle Checkboxen durchlaufen, mittels Reflection und anhand der Checked-Property deinen bedingten Code ausführen.

    C#-Quellcode

    1. foreach (var checkbox in GetType().GetFields().Where(f => f.GetType().Name == typeof(CheckBox).Name)) {
    2. // Behandle hier das Krams
    3. }
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.
    Najaaa, es soll ja CheckBox-spezifisch was gemacht werden. Dementsprechend wäre ein gemeinsames Abfrühstücken aller CheckBoxen nicht sinnvoll, da man ja dann doch wieder zwischen allen unterscheiden muss. Ich wäre dann eher bei solch einer konservativen Sache, aber auch wieder mit If.

    VB.NET-Quellcode

    1. Private Sub InsertBlocks()
    2. InsertBlockFor(CheckBox1, "Text1")
    3. InsertBlockFor(CheckBox2, "Text2")
    4. InsertBlockFor(CheckBox3, "Text3")
    5. InsertBlockFor(CheckBox4, "Text4")
    6. '…
    7. End Sub
    8. Private Sub InsertBlockFor(CheckBox As CheckBox, Text As String)
    9. If Not CheckBox.Checked Then Return
    10. 'irgendwas mit Text machen
    11. End Sub
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Grundsätzlich hast du natürlich Recht. Eine If-Abfragenfolge ist bei kleineren Mengen auch deutlich sinnvoller.

    Wenn wir allerdings über 12 Checkboxen (oder auch mehr) reden, dann kann es schon sinnvoller sein, die in wenig Code abzufrühstücken und mit entsprechender parametrierung die zu unterscheiden.

    Der Ansatz von mir wäre auch dem, was du geschrieben hast, sehr ähnlich.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.
    Mir ist der Sinn hinter "Select / Case" und "If / Then" schon bewußt. Macht euch jetzt nicht deshalb verückt. Wenn es so schlank und rank nicht geht ist das mit IF/Then ok. Sieht halt nur schei... aus.

    Der Erfinder von ​Select Case hat halt gedacht warum soll ich den Rest prüfen nachdem der erste Case eingetreten ist. Wir reden hier aber über Case True, nicht über Case 1 oder Case 2... (um es einfach zu halten). Der Erfinder von If Then hat halt gedacht wenn einer ​If bla And blub then prüfe ich trotzdem blub obwohl bla schon nicht erfüllt ist. Der eine war faul und der andere halt neugierig :)

    JLH schrieb:

    Der Erfinder von ​Select Case hat halt gedacht warum soll ich den Rest prüfen nachdem der erste Case eingetreten ist.

    JLH schrieb:

    Der eine war faul und der andere halt neugierig


    Ich glaube da hast du was grundsätzlich misverstanden.

    Diese beiden Konstrukte sehen nicht nur anders aus, sondern sie funktionieren auch gänzlich anders. Das ist der Sinn dahinter und auch der Grund, warum switch/case in unterschiedlichen Sprachen auch unterschiedliche Scopes hat.
    Mit Faulheit/Neugierde hat das nichts zu tun.

    Ich hab mal was vorbereitet:

    Folgender Code zeigt den Unterschied:

    C-Quellcode

    1. void foo() {
    2. int x = 1;
    3. switch (x) {
    4. case 0:
    5. printf("x is 0");
    6. break;
    7. case 10:
    8. printf("x is 10");
    9. break;
    10. }
    11. }


    Hier ist ein ganz einfacher Switch-Case. Ähnlich wie du es oben hast.
    Schauen wir uns die CPU-Anweisungen an:

    Quellcode

    1. foo(): ; hier beginnt die Funktion
    2. push rbp
    3. mov rbp, rsp
    4. sub rsp, 16
    5. mov DWORD PTR [rbp-4], 1 ; hier sagen wir x = 1
    6. cmp DWORD PTR [rbp-4], 0 ; hier vergleichen wir x mit dem Wert 0 und setzen einen Wert in einem Register
    7. je .L2 ; WENN die Werte gleich sind, dann springe (goto) zu .L2
    8. cmp DWORD PTR [rbp-4], 10 ; vergleiche x mit 10 und setze einen Wert im Register
    9. je .L3 ; WENN die Werte gleich sind, dann springe (goto) zu .L3
    10. jmp .L5 ; springe (goto) zu .L5
    11. .L2:
    12. mov edi, OFFSET FLAT:.LC0
    13. mov eax, 0
    14. call printf
    15. jmp .L4
    16. .L3:
    17. mov edi, OFFSET FLAT:.LC1
    18. mov eax, 0
    19. call printf
    20. nop
    21. .L4:
    22. .L5:
    23. nop
    24. leave
    25. ret


    Wir sehen hier also, es wird immer der Wert verglichen und dann sofort gesprungen, sobald die Bedingung zutrifft, also die Werte gleich sind.

    Schauen wir uns nun einen if/else Block an:

    C-Quellcode

    1. void bar() {
    2. int x = 1;
    3. if (x == 0) {
    4. printf("x is 0");
    5. } else if (x == 10) {
    6. printf("x is 10");
    7. }
    8. }


    Hier ebenfalls ganz einfach mit zwei Bedingungen:

    Quellcode

    1. bar(): ; hier beginnt die Funktion
    2. push rbp
    3. mov rbp, rsp
    4. sub rsp, 16
    5. mov DWORD PTR [rbp-4], 1 ; hier setzen wir wieder x = 1
    6. cmp DWORD PTR [rbp-4], 0 ; vergleiche x mit 0
    7. jne .L9 ; wenn die Werte NICHT GLEICH sind, dann springe (goto) zur nächsten Bedingung (.L9)
    8. mov edi, OFFSET FLAT:.LC0 ; die Werte sind gleich, führe bedingten Code aus
    9. mov eax, 0
    10. call printf
    11. jmp .L11 ; springe (goto) zum Ende der Funktion
    12. .L9:
    13. cmp DWORD PTR [rbp-4], 10 ; vergleiche x mit 10
    14. jne .L11 ; wenn die Werte NICHT GLEICH sind, dann springe (goto) zum Ende der Funktion
    15. mov edi, OFFSET FLAT:.LC1
    16. mov eax, 0
    17. call printf
    18. .L11:
    19. nop
    20. leave
    21. ret


    Wie du hoffentlich siehst, da gibt's einen (relativ) großen Unterschied zwischen den Beiden; weshalb das mit dem Switch nicht geht, dass der ohne Weitere einfach die nächsten Bedingungen prüft.
    Zumal moderne Hochsprachen einen Schutz gegen Fall-Through haben, weshalb mein Beispiel oben mit Duff's Device nicht in Rust, C# (VB), Java, oder anderen Hochsprachen geht.
    C und C++ lassen es mit entsprechenden Compilereinstellungen allerdings problemlos durch.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.
    Was noch dazukommt, ist wohl, dass das Select Case True falsch verstanden wird. Da manche Sachen nicht in die Bedigung nach Select Case dürfen, verwendet man Select Case True, um die erste Bedingung auch bei Objekten zu finden, die zutrifft. Es gibt, wie geschrieben, einfach kein »prüfe weitere zutreffende Fälle« bei Select Case - im Gegensatz zu C#s switch.
    Aber auch bei nicht-Select Case True wird immer nur der erste zutreffende Fall abgearbeitet:

    VB.NET-Quellcode

    1. Dim x = 0
    2. Select Case x
    3. Case 0 : MessageBox.Show("0")
    4. Case 0 : MessageBox.Show("1") 'wird nie erreicht/aufgerufen
    5. End Select

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    siycah schrieb:

    Aber in modernen Hochsprachen machen solche Konstrukte keinen Sinn, weshalb man auch nicht mehr durchfallen kann
    Was ich viel eher nicht verstehe ist, gerade weil man nicht mehr durchfallen kann, warum muss man da immer break; hintippern in c#? Dieses break ist so wie ich verstehe was in c das durchfallen verhindern würde.

    siycah schrieb:

    da gibt's einen (relativ) großen Unterschied zwischen den Beiden
    Ich sehe da keinen Unterschied. Also ja die Assembly sieht anders aus, aber würde ich die Funktion in Assembly selbst schreiben wollen, täte ich mich doch wohl für die Variante entscheiden, die das If erzeugt, in dem Sinne dass das Ziel das gleiche ist, der Code aber kürzer und verständlicher.
    Dies widerum lässt mich wundern warum Select Case überhaupt noch anders funktionieren muss. Sollte er doch eher zu einem syntactic sugar degradieren.
    Wobei das auch nur in vb Sinn hätte, c#'s obligatorisches break; macht switch case für mich vollständig überflüssig.

    Da wäre ich auch mal gespannt, ob vbs Select Case und c#s switch case überhaupt dasselbe sind.

    Was das Thema aber angeht denke ich könnte man z.b. auch alle Bedingungen in ein Linq stopfen, wenn "füge Block1 ein / füge Block2 ein" entsprechend verallgemeinert werden kann.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Haudruferzappeltnoch schrieb:

    Was ich viel eher nicht verstehe ist, gerade weil man nicht mehr durchfallen kann, warum muss man da immer break; hintippern in c#? Dieses break ist so wie verstehe was in c das durchfallen verhindern würde.


    Das break ist nicht obligatorisch, aber es muss eine Anweisung auftauchen, die den Steuerungsfluss beeinflusst.
    Überlicherweise wird ein break genommen, damit die Kontrollstruktur (switch) verlassen wird.
    Es kann aber auch genau so gut ein return, oder auch ein goto rein.

    Der Grund, dass ein Keyword obligatorisch ist, ist dass man genau sieht was da passiert. VB abstrahiert das weg - das finde ich schlimm.

    Haudruferzappeltnoch schrieb:

    Ich sehe da keinen Unterschied.

    Da ist ein gewaltiger Unterschied. je vs jne.

    Haudruferzappeltnoch schrieb:

    Also ja die Assembly sieht anders aus

    Genau das ist der Punkt. Die CPU-Anweisungen selber sind unterschiedlich.
    Ich habe den o.g. Asm im Debug-Mode geschrieben. Spätestens wenn man Optimierungen einschaltet, sieht man einen noch gewaltigeren Unterschied:

    -O1:

    Quellcode

    1. .LC0:
    2. .string "x is 0" // Zeichenkette für x == 0
    3. .LC1:
    4. .string "x is 10" // Zeichenkette für x == 10
    5. .LC2:
    6. .string "x is 5" // Zeichenkette für x == 5
    7. .LC3:
    8. .string "x is 8" // Zeichenkette für x == 8
    9. .LC4:
    10. .string "x is 1" // Zeichenkette für x == 1
    11. // Funktion foo(int)
    12. foo(int):
    13. cmp edi, 10 // Vergleiche Eingabewert mit 10
    14. ja .L10 // Springe zu .L10, falls Wert > 10
    15. sub rsp, 8 // Stack anpassen (Platz reservieren)
    16. mov edi, edi // Wert bleibt gleich (keine Änderung)
    17. jmp [QWORD PTR .L4[0+rdi*8]] // Springe zu Adresse aus Sprungtabelle
    18. .L4:
    19. .quad .L8 // Fall x == 0
    20. .quad .L7 // Fall x == 1
    21. .quad .L1 // Fall x == 2
    22. .quad .L1 // Fall x == 3
    23. .quad .L1 // Fall x == 4
    24. .quad .L6 // Fall x == 5
    25. .quad .L1 // Fall x == 6
    26. .quad .L1 // Fall x == 7
    27. .quad .L5 // Fall x == 8
    28. .quad .L1 // Fall x == 9
    29. .quad .L3 // Fall x == 10
    30. .L8:
    31. mov edi, OFFSET FLAT:.LC0 // Adresse von "x is 0" laden
    32. mov eax, 0
    33. call printf // printf("x is 0")
    34. .L1:
    35. add rsp, 8 // Stack zurücksetzen
    36. ret // Rückkehr aus Funktion
    37. .L3:
    38. mov edi, OFFSET FLAT:.LC1 // Adresse von "x is 10" laden
    39. mov eax, 0
    40. call printf // printf("x is 10")
    41. jmp .L1 // Rückkehr
    42. .L6:
    43. mov edi, OFFSET FLAT:.LC2 // Adresse von "x is 5" laden
    44. mov eax, 0
    45. call printf // printf("x is 5")
    46. jmp .L1
    47. .L5:
    48. mov edi, OFFSET FLAT:.LC3 // Adresse von "x is 8" laden
    49. mov eax, 0
    50. call printf // printf("x is 8")
    51. jmp .L1
    52. .L7:
    53. mov edi, OFFSET FLAT:.LC4 // Adresse von "x is 1" laden
    54. mov eax, 0
    55. call printf // printf("x is 1")
    56. jmp .L1
    57. .L10:
    58. ret // Rückkehr, falls x > 10
    59. // Funktion bar(int)
    60. bar(int):
    61. sub rsp, 8 // Stack anpassen
    62. test edi, edi // Prüfe, ob Wert 0 ist
    63. je .L17 // Springe zu .L17, falls ja
    64. cmp edi, 10 // Prüfe, ob Wert 10 ist
    65. je .L18 // Springe zu .L18, falls ja
    66. .L13:
    67. add rsp, 8 // Stack zurücksetzen
    68. ret // Rückkehr
    69. .L17:
    70. mov edi, OFFSET FLAT:.LC0 // "x is 0"
    71. mov eax, 0
    72. call printf // printf("x is 0")
    73. jmp .L13
    74. .L18:
    75. mov edi, OFFSET FLAT:.LC1 // "x is 10"
    76. mov eax, 0
    77. call printf // printf("x is 10")
    78. jmp .L13


    Aktiviert man noch agressivere Optimierungen, sieht das natürlich nochmal anders aus.

    Haudruferzappeltnoch schrieb:

    täte ich mich doch wohl für die Variante entscheiden, die das If erzeugt.

    Switch-Cases sind schneller. In C# wird das noch etwas anders gehandhabt, wegen der neuen Pattern-Matching Syntax, aber abgesehen von der Tatsache, dass es lesbarer ist wenn man mehr als zwei/drei Bedingungen hat, ist es in 9/10 Fällen bei einfachen Bedingungen ein Switch-Case schneller.

    Schau dir mal an, was ich hierüber geschrieben habe.

    Außerdem werden ab einer gewissen Menge auch Ifs zu Switch-Cases umgewandelt, wenn möglich.

    Nehmen wir mal folgenden angepassten Code:

    C-Quellcode

    1. void bar(int x) {
    2. if (x == 0) {
    3. printf("x is 0");
    4. } else if (x == 10) {
    5. printf("x is 10");
    6. } else if (x == 5) {
    7. printf("x is 5");
    8. } else if (x == 8) {
    9. printf("x is 8");
    10. } else if (x == 1) {
    11. printf("x is 1");
    12. }
    13. }


    Mit Optimierungen: (-O1)

    Quellcode

    1. bar(int):
    2. cmp edi, 10
    3. ja .L10
    4. mov edi, edi
    5. jmp [QWORD PTR .L13[0+rdi*8]]
    6. .L13:
    7. .quad .L17
    8. .quad .L16
    9. .quad .L10
    10. .quad .L10
    11. .quad .L10
    12. .quad .L15
    13. .quad .L10
    14. .quad .L10
    15. .quad .L14
    16. .quad .L10
    17. .quad .L12
    18. .L10:
    19. ret
    20. .L17:
    21. mov edi, OFFSET FLAT:.LC0
    22. xor eax, eax
    23. jmp printf
    24. .L16:
    25. mov edi, OFFSET FLAT:.LC4
    26. xor eax, eax
    27. jmp printf
    28. .L15:
    29. mov edi, OFFSET FLAT:.LC2
    30. xor eax, eax
    31. jmp printf
    32. .L14:
    33. mov edi, OFFSET FLAT:.LC3
    34. xor eax, eax
    35. jmp printf
    36. .L12:
    37. mov edi, OFFSET FLAT:.LC1
    38. xor eax, eax
    39. jmp printf


    Ohne Optimierungen: (-O0)

    Quellcode

    1. bar(int):
    2. push rbp
    3. mov rbp, rsp
    4. sub rsp, 16
    5. mov DWORD PTR [rbp-4], edi
    6. cmp DWORD PTR [rbp-4], 0
    7. jne .L10
    8. mov edi, OFFSET FLAT:.LC0
    9. mov eax, 0
    10. call printf
    11. jmp .L15
    12. .L10:
    13. cmp DWORD PTR [rbp-4], 10
    14. jne .L12
    15. mov edi, OFFSET FLAT:.LC1
    16. mov eax, 0
    17. call printf
    18. jmp .L15
    19. .L12:
    20. cmp DWORD PTR [rbp-4], 5
    21. jne .L13
    22. mov edi, OFFSET FLAT:.LC2
    23. mov eax, 0
    24. call printf
    25. jmp .L15
    26. .L13:
    27. cmp DWORD PTR [rbp-4], 8
    28. jne .L14
    29. mov edi, OFFSET FLAT:.LC3
    30. mov eax, 0
    31. call printf
    32. jmp .L15
    33. .L14:
    34. cmp DWORD PTR [rbp-4], 1
    35. jne .L15
    36. mov edi, OFFSET FLAT:.LC4
    37. mov eax, 0
    38. call printf
    39. .L15:
    40. nop
    41. leave
    42. ret


    Haudruferzappeltnoch schrieb:

    Da wäre ich auch mal gespannt, ob vbs Select Case und c#s switch case überhaupt dasselbe sind.


    Kann man doch einfach herausfinden:

    Spoiler anzeigen

    C#-Quellcode

    1. namespace ConsoleApp3 {
    2. internal class Program {
    3. static void Main(string[] args) {
    4. var rand = new Random().Next(1, 6); // Generates a random number between 1 and 5
    5. PrintNumber(rand);
    6. }
    7. static void PrintNumber(int num) {
    8. switch (num) {
    9. case 0:
    10. Console.WriteLine("You rolled a Zero!");
    11. break;
    12. case 1:
    13. Console.WriteLine("You rolled a One!");
    14. break;
    15. case 2:
    16. Console.WriteLine("You rolled a Two!");
    17. break;
    18. case 3:
    19. Console.WriteLine("You rolled a Three!");
    20. break;
    21. case 4:
    22. Console.WriteLine("You rolled a Four!");
    23. break;
    24. case 5:
    25. Console.WriteLine("You rolled a Five!");
    26. break;
    27. default:
    28. Console.WriteLine("Number not recognized");
    29. break;
    30. }
    31. }
    32. }
    33. }


    C# MSIL (Debug):

    Quellcode

    1. // Type: ConsoleApp3.Program
    2. // Assembly: ConsoleApp3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    3. // MVID: BA4D4D08-95F4-4A38-89CB-C40D3ED055D6
    4. // Location: C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\net9.0\ConsoleApp3.dll
    5. // Sequence point data and variable names from C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\net9.0\ConsoleApp3.pdb
    6. .class private auto ansi beforefieldinit
    7. ConsoleApp3.Program
    8. extends [System.Runtime]System.Object
    9. {
    10. .method private hidebysig static void
    11. Main(
    12. string[] args
    13. ) cil managed
    14. {
    15. .entrypoint
    16. .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(unsigned int8)
    17. = (01 00 01 00 00 ) // .....
    18. // unsigned int8(1) // 0x01
    19. .maxstack 3
    20. .locals init (
    21. [0] int32 rand
    22. )
    23. // [3 41 - 3 42]
    24. IL_0000: nop
    25. // [4 13 - 4 48]
    26. IL_0001: newobj instance void [System.Runtime]System.Random::.ctor()
    27. IL_0006: ldc.i4.1
    28. IL_0007: ldc.i4.6
    29. IL_0008: callvirt instance int32 [System.Runtime]System.Random::Next(int32, int32)
    30. IL_000d: stloc.0 // rand
    31. // [5 9 - 5 10]
    32. IL_000e: ret
    33. } // end of method Program::Main
    34. .method private hidebysig static void
    35. PrintNumber(
    36. int32 num
    37. ) cil managed
    38. {
    39. .maxstack 1
    40. .locals init (
    41. [0] int32 V_0,
    42. [1] int32 V_1
    43. )
    44. // [7 42 - 7 43]
    45. IL_0000: nop
    46. // [8 13 - 8 25]
    47. IL_0001: ldarg.0 // num
    48. IL_0002: stloc.1 // V_1
    49. IL_0003: ldloc.1 // V_1
    50. IL_0004: stloc.0 // V_0
    51. IL_0005: ldloc.0 // V_0
    52. IL_0006: switch (IL_0025, IL_0032, IL_003f, IL_004c, IL_0059, IL_0066)
    53. IL_0023: br.s IL_0073
    54. // [10 21 - 10 61]
    55. IL_0025: ldstr "You rolled a Zero!"
    56. IL_002a: call void [System.Console]System.Console::WriteLine(string)
    57. IL_002f: nop
    58. // [11 21 - 11 27]
    59. IL_0030: br.s IL_0080
    60. // [13 21 - 13 60]
    61. IL_0032: ldstr "You rolled a One!"
    62. IL_0037: call void [System.Console]System.Console::WriteLine(string)
    63. IL_003c: nop
    64. // [14 21 - 14 27]
    65. IL_003d: br.s IL_0080
    66. // [16 21 - 16 60]
    67. IL_003f: ldstr "You rolled a Two!"
    68. IL_0044: call void [System.Console]System.Console::WriteLine(string)
    69. IL_0049: nop
    70. // [17 21 - 17 27]
    71. IL_004a: br.s IL_0080
    72. // [19 21 - 19 62]
    73. IL_004c: ldstr "You rolled a Three!"
    74. IL_0051: call void [System.Console]System.Console::WriteLine(string)
    75. IL_0056: nop
    76. // [20 21 - 20 27]
    77. IL_0057: br.s IL_0080
    78. // [22 21 - 22 61]
    79. IL_0059: ldstr "You rolled a Four!"
    80. IL_005e: call void [System.Console]System.Console::WriteLine(string)
    81. IL_0063: nop
    82. // [23 21 - 23 27]
    83. IL_0064: br.s IL_0080
    84. // [25 21 - 25 61]
    85. IL_0066: ldstr "You rolled a Five!"
    86. IL_006b: call void [System.Console]System.Console::WriteLine(string)
    87. IL_0070: nop
    88. // [26 21 - 26 27]
    89. IL_0071: br.s IL_0080
    90. // [28 21 - 28 64]
    91. IL_0073: ldstr "Number not recognized"
    92. IL_0078: call void [System.Console]System.Console::WriteLine(string)
    93. IL_007d: nop
    94. // [29 21 - 29 27]
    95. IL_007e: br.s IL_0080
    96. // [31 9 - 31 10]
    97. IL_0080: ret
    98. } // end of method Program::PrintNumber
    99. .method public hidebysig specialname rtspecialname instance void
    100. .ctor() cil managed
    101. {
    102. .maxstack 8
    103. IL_0000: ldarg.0 // this
    104. IL_0001: call instance void [System.Runtime]System.Object::.ctor()
    105. IL_0006: nop
    106. IL_0007: ret
    107. } // end of method Program::.ctor
    108. } // end of class ConsoleApp3.Program


    C# MSIL (Release):

    Quellcode

    1. // Type: ConsoleApp3.Program
    2. // Assembly: ConsoleApp3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    3. // MVID: 53754F5C-A3DF-453B-BEC0-E39D870A82F9
    4. // Location: C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp3\bin\Release\net9.0\ConsoleApp3.dll
    5. // Sequence point data and variable names from C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp3\bin\Release\net9.0\ConsoleApp3.pdb
    6. .class private auto ansi beforefieldinit
    7. ConsoleApp3.Program
    8. extends [System.Runtime]System.Object
    9. {
    10. .method private hidebysig static void
    11. Main(
    12. string[] args
    13. ) cil managed
    14. {
    15. .entrypoint
    16. .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(unsigned int8)
    17. = (01 00 01 00 00 ) // .....
    18. // unsigned int8(1) // 0x01
    19. .maxstack 8
    20. // [4 13 - 4 48]
    21. IL_0000: newobj instance void [System.Runtime]System.Random::.ctor()
    22. IL_0005: ldc.i4.1
    23. IL_0006: ldc.i4.6
    24. IL_0007: callvirt instance int32 [System.Runtime]System.Random::Next(int32, int32)
    25. // [5 13 - 5 31]
    26. IL_000c: call void ConsoleApp3.Program::PrintNumber(int32)
    27. // [6 9 - 6 10]
    28. IL_0011: ret
    29. } // end of method Program::Main
    30. .method private hidebysig static void
    31. PrintNumber(
    32. int32 num
    33. ) cil managed
    34. {
    35. .maxstack 1
    36. IL_0000: ldarg.0 // num
    37. IL_0001: switch (IL_0020, IL_002b, IL_0036, IL_0041, IL_004c, IL_0057)
    38. IL_001e: br.s IL_0062
    39. // [11 21 - 11 61]
    40. IL_0020: ldstr "You rolled a Zero!"
    41. IL_0025: call void [System.Console]System.Console::WriteLine(string)
    42. // [12 21 - 12 27]
    43. IL_002a: ret
    44. // [14 21 - 14 60]
    45. IL_002b: ldstr "You rolled a One!"
    46. IL_0030: call void [System.Console]System.Console::WriteLine(string)
    47. // [15 21 - 15 27]
    48. IL_0035: ret
    49. // [17 21 - 17 60]
    50. IL_0036: ldstr "You rolled a Two!"
    51. IL_003b: call void [System.Console]System.Console::WriteLine(string)
    52. // [18 21 - 18 27]
    53. IL_0040: ret
    54. // [20 21 - 20 62]
    55. IL_0041: ldstr "You rolled a Three!"
    56. IL_0046: call void [System.Console]System.Console::WriteLine(string)
    57. // [21 21 - 21 27]
    58. IL_004b: ret
    59. // [23 21 - 23 61]
    60. IL_004c: ldstr "You rolled a Four!"
    61. IL_0051: call void [System.Console]System.Console::WriteLine(string)
    62. // [24 21 - 24 27]
    63. IL_0056: ret
    64. // [26 21 - 26 61]
    65. IL_0057: ldstr "You rolled a Five!"
    66. IL_005c: call void [System.Console]System.Console::WriteLine(string)
    67. // [27 21 - 27 27]
    68. IL_0061: ret
    69. // [29 21 - 29 64]
    70. IL_0062: ldstr "Number not recognized"
    71. IL_0067: call void [System.Console]System.Console::WriteLine(string)
    72. // [32 9 - 32 10]
    73. IL_006c: ret
    74. } // end of method Program::PrintNumber
    75. .method public hidebysig specialname rtspecialname instance void
    76. .ctor() cil managed
    77. {
    78. .maxstack 8
    79. IL_0000: ldarg.0 // this
    80. IL_0001: call instance void [System.Runtime]System.Object::.ctor()
    81. IL_0006: ret
    82. } // end of method Program::.ctor
    83. } // end of class ConsoleApp3.Program




    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System
    2. Module Program
    3. Sub Main(args As String())
    4. Dim rand = New Random().Next(1, 6)
    5. PrintMessage(rand)
    6. End Sub
    7. Sub PrintMessage(num As Int32)
    8. Select Case num
    9. Case 0
    10. Console.WriteLine("You rolled a zero!")
    11. Case 1
    12. Console.WriteLine("You rolled a one!")
    13. Case 2
    14. Console.WriteLine("You rolled a two!")
    15. Case 3
    16. Console.WriteLine("You rolled a three!")
    17. Case 4
    18. Console.WriteLine("You rolled a four!")
    19. Case 5
    20. Console.WriteLine("You rolled a five!")
    21. Case Else
    22. Console.WriteLine("You rolled an invalid number!")
    23. End Select
    24. End Sub
    25. End Module


    VB.NET MSIL (Debug):

    Quellcode

    1. // Type: ConsoleApp1.Program
    2. // Assembly: ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    3. // MVID: 12C1F6BE-6BBA-4D2C-A97C-DF28385F7573
    4. // Location: C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp1\bin\Debug\net9.0\ConsoleApp1.dll
    5. // Sequence point data and variable names from C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp1\bin\Debug\net9.0\ConsoleApp1.pdb
    6. .class private sealed auto ansi
    7. ConsoleApp1.Program
    8. extends [System.Runtime]System.Object
    9. {
    10. .custom instance void [Microsoft.VisualBasic.Core]Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute::.ctor()
    11. = (01 00 00 00 )
    12. .method public static void
    13. Main(
    14. string[] args
    15. ) cil managed
    16. {
    17. .entrypoint
    18. .custom instance void [System.Runtime]System.STAThreadAttribute::.ctor()
    19. = (01 00 00 00 )
    20. .maxstack 3
    21. .locals init (
    22. [0] int32 rand
    23. )
    24. // [4 5 - 4 31]
    25. IL_0000: nop
    26. // [5 13 - 5 43]
    27. IL_0001: newobj instance void [System.Runtime]System.Random::.ctor()
    28. IL_0006: ldc.i4.1
    29. IL_0007: ldc.i4.6
    30. IL_0008: callvirt instance int32 [System.Runtime]System.Random::Next(int32, int32)
    31. IL_000d: stloc.0 // rand
    32. // [6 5 - 6 12]
    33. IL_000e: ret
    34. } // end of method Program::Main
    35. .method public static void
    36. PrintMessage(
    37. int32 num
    38. ) cil managed
    39. {
    40. .maxstack 1
    41. .locals init (
    42. [0] int32 V_0
    43. )
    44. // [8 5 - 8 35]
    45. IL_0000: nop
    46. // [9 9 - 9 24]
    47. IL_0001: nop
    48. IL_0002: ldarg.0 // num
    49. IL_0003: stloc.0 // V_0
    50. IL_0004: ldloc.0 // V_0
    51. IL_0005: switch (IL_0024, IL_0032, IL_0040, IL_004e, IL_005c, IL_006a)
    52. IL_0022: br.s IL_0078
    53. // [10 13 - 10 19]
    54. IL_0024: nop
    55. // [11 17 - 11 56]
    56. IL_0025: ldstr "You rolled a zero!"
    57. IL_002a: call void [System.Console]System.Console::WriteLine(string)
    58. IL_002f: nop
    59. IL_0030: br.s IL_0086
    60. // [12 13 - 12 19]
    61. IL_0032: nop
    62. // [13 17 - 13 55]
    63. IL_0033: ldstr "You rolled a one!"
    64. IL_0038: call void [System.Console]System.Console::WriteLine(string)
    65. IL_003d: nop
    66. IL_003e: br.s IL_0086
    67. // [14 13 - 14 19]
    68. IL_0040: nop
    69. // [15 17 - 15 55]
    70. IL_0041: ldstr "You rolled a two!"
    71. IL_0046: call void [System.Console]System.Console::WriteLine(string)
    72. IL_004b: nop
    73. IL_004c: br.s IL_0086
    74. // [16 13 - 16 19]
    75. IL_004e: nop
    76. // [17 17 - 17 57]
    77. IL_004f: ldstr "You rolled a three!"
    78. IL_0054: call void [System.Console]System.Console::WriteLine(string)
    79. IL_0059: nop
    80. IL_005a: br.s IL_0086
    81. // [18 13 - 18 19]
    82. IL_005c: nop
    83. // [19 17 - 19 56]
    84. IL_005d: ldstr "You rolled a four!"
    85. IL_0062: call void [System.Console]System.Console::WriteLine(string)
    86. IL_0067: nop
    87. IL_0068: br.s IL_0086
    88. // [20 13 - 20 19]
    89. IL_006a: nop
    90. // [21 17 - 21 56]
    91. IL_006b: ldstr "You rolled a five!"
    92. IL_0070: call void [System.Console]System.Console::WriteLine(string)
    93. IL_0075: nop
    94. IL_0076: br.s IL_0086
    95. // [23 13 - 23 22]
    96. IL_0078: nop
    97. // [24 17 - 24 67]
    98. IL_0079: ldstr "You rolled an invalid number!"
    99. IL_007e: call void [System.Console]System.Console::WriteLine(string)
    100. IL_0083: nop
    101. IL_0084: br.s IL_0086
    102. // [25 9 - 25 19]
    103. IL_0086: nop
    104. // [26 5 - 26 12]
    105. IL_0087: ret
    106. } // end of method Program::PrintMessage
    107. } // end of class ConsoleApp1.Program


    VB.NET MSIL (Release):

    Quellcode

    1. // Type: ConsoleApp1.Program
    2. // Assembly: ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    3. // MVID: 9F318A06-FBE8-4B47-B326-5CAA55CCB5EE
    4. // Location: C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp1\bin\Release\net9.0\ConsoleApp1.dll
    5. // Sequence point data and variable names from C:\Users\simon\source\repos\ConsoleApp3\ConsoleApp1\bin\Release\net9.0\ConsoleApp1.pdb
    6. .class private sealed auto ansi
    7. ConsoleApp1.Program
    8. extends [System.Runtime]System.Object
    9. {
    10. .custom instance void [Microsoft.VisualBasic.Core]Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute::.ctor()
    11. = (01 00 00 00 )
    12. .method public static void
    13. Main(
    14. string[] args
    15. ) cil managed
    16. {
    17. .entrypoint
    18. .custom instance void [System.Runtime]System.STAThreadAttribute::.ctor()
    19. = (01 00 00 00 )
    20. .maxstack 8
    21. // [5 13 - 5 43]
    22. IL_0000: newobj instance void [System.Runtime]System.Random::.ctor()
    23. IL_0005: ldc.i4.1
    24. IL_0006: ldc.i4.6
    25. IL_0007: callvirt instance int32 [System.Runtime]System.Random::Next(int32, int32)
    26. // [6 9 - 6 27]
    27. IL_000c: call void ConsoleApp1.Program::PrintMessage(int32)
    28. // [7 5 - 7 12]
    29. IL_0011: ret
    30. } // end of method Program::Main
    31. .method public static void
    32. PrintMessage(
    33. int32 num
    34. ) cil managed
    35. {
    36. .maxstack 1
    37. .locals init (
    38. [0] int32 V_0
    39. )
    40. // [10 9 - 10 24]
    41. IL_0000: ldarg.0 // num
    42. IL_0001: stloc.0 // V_0
    43. IL_0002: ldloc.0 // V_0
    44. IL_0003: switch (IL_0022, IL_002d, IL_0038, IL_0043, IL_004e, IL_0059)
    45. IL_0020: br.s IL_0064
    46. // [12 17 - 12 56]
    47. IL_0022: ldstr "You rolled a zero!"
    48. IL_0027: call void [System.Console]System.Console::WriteLine(string)
    49. IL_002c: ret
    50. // [14 17 - 14 55]
    51. IL_002d: ldstr "You rolled a one!"
    52. IL_0032: call void [System.Console]System.Console::WriteLine(string)
    53. IL_0037: ret
    54. // [16 17 - 16 55]
    55. IL_0038: ldstr "You rolled a two!"
    56. IL_003d: call void [System.Console]System.Console::WriteLine(string)
    57. IL_0042: ret
    58. // [18 17 - 18 57]
    59. IL_0043: ldstr "You rolled a three!"
    60. IL_0048: call void [System.Console]System.Console::WriteLine(string)
    61. IL_004d: ret
    62. // [20 17 - 20 56]
    63. IL_004e: ldstr "You rolled a four!"
    64. IL_0053: call void [System.Console]System.Console::WriteLine(string)
    65. IL_0058: ret
    66. // [22 17 - 22 56]
    67. IL_0059: ldstr "You rolled a five!"
    68. IL_005e: call void [System.Console]System.Console::WriteLine(string)
    69. IL_0063: ret
    70. // [25 17 - 25 67]
    71. IL_0064: ldstr "You rolled an invalid number!"
    72. IL_0069: call void [System.Console]System.Console::WriteLine(string)
    73. // [27 5 - 27 12]
    74. IL_006e: ret
    75. } // end of method Program::PrintMessage
    76. } // end of class ConsoleApp1.Program



    Edit: Habe die diff-Datei hier mal angehangen; darin ist der Diff zwischen VB (Release) und C# (Release).

    Edit 2: Die Debug-Varianten habe ich ebenfalls als Diff hochgeladen. Könnt ihr auch mit Meld anschauen: https://meldmerge.org/
    Dateien
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „siycah“ ()

    Also nur dass du mich verstehst.
    Unterschiede in den Assemblies finde ich dann relevant wenn man die Hochsprache bewerten will, also eben sowas wie ob vb select c# switch "gleich" sind.
    Aber mit Unterschieden in den Assemblies kann ich doch nicht Unterschiede in der Hochsprache rechtfertigen. Das is doch die falsche Denkrichtung. Wenn zwei verschiedene Codes in Hochsprache zum selben Ergebnis führen wäre es doch wünschenswert, wenn die Compiler gleiche Assemblies erzeugen.
    (Dass das in der Realität nicht immer hinhaut, ist vollkommen klar und verständlich, das kennt man ja am besten vom SQL.)

    Und wenn ich nun das vorwegstelle, dass der Compiler das gebacken kriege, dann muss ich mich widerum fragen, warum hätte man diese Redundanz dann in der Hochsprache.
    Nu kriegts der Compiler aber nich hin, dann ist das doch ein Stolperstein, dass ich überhaupt die "falsche" Variante wählen kann.

    Das mit den diffs hab ich leider nicht verstanden, ich sehe da nur einen Code. Aber du musst das nicht für mich rausfinden, das meinte ich nur, weil switch ja diesen Background hat durch c und Select gabs in vb6 aber auch schon.
    Natürlich kann und muss man das.

    Haudruferzappeltnoch schrieb:

    Wenn zwei verschiedene Codes in Hochsprache zum selben Ergebnis führen


    Wenn ich dreimal rechts fahre, fahre ich auch wieder links. Das Ergebnis ist das selbe, aber der Weg ein Anderer.

    C# ist mit VB kompatibel, aber in jederlei Hinsicht eine kompetentere und komplexere Sprache.
    VB stammt von BASIC ab und war damals ein einfacher Weg, damit jedermann Software bauen kann. Oma hat damit ihre Rezepte digital gemacht und erweiterbar.
    Der Opa hat damit ein Ding gebaut, womit den Anteil an Filet in einem Fisch berechnen konnte, wenn er angeln war.
    Und der Onkel hat so seinen Weg in seine IT-Karriere entdeckt.

    So oder so ähnlich war es halt damals gedacht und teilweise auch so gelebt.
    Mit BASIC hat Microsoft auch seine Anfänge auf dem Altair 8800 gehabt - dass die in den 90ern und 00ern ihre Tradition aufrechterhalten wollten, kann ich verstehen.
    Es war allerdings auch damals schon so, dass kaum professionelle Software darin geschrieben wurde.

    Mit der Einführung von dotnet hat MS damals VB mitgeschlürt, weil sie halt eine Userbase hatten. Der Fokus ist seitdem aber ganz klar auf C#, welche dazu gebaut wurde, eine Verbesserung über VB und gar C++ im Userspace zu sein.
    Weil das dotnet Framework allerdings auch C# abgestimmt ist (Sieht man auch am MSIL) und VB eine "einfache" Sprache sein soll (ist sie nicht, aber sei's drum), wurden Features ausgelassen und es wurden Hilfsmittel eingebaut, damit die kompatibel und abwärtskompatibel bleiben.

    Nur um zu verdeutlichen, um welche Zahlen wir hier reden:

    VB machte zu Spitzenzeiten 0,85% aus und ist mittlerweile bei 0,3%.
    C# liegt im gleichen Zeitraum bei 5% bis über 9% zu Spitzenzeiten.

    Haudruferzappeltnoch schrieb:

    Und wenn ich nun das vorwegstelle, dass der Compiler das gebacken kriege, dann muss ich mich widerum fragen, warum hätte man diese Redundanz dann in der Hochsprache.


    Es gibt viele Gründe. Egal was ich hier tippe, das klingt als würde ich gegen VB-Entwickler wettern, was nicht der Fall ist.
    Am Ende der Tages wird man mit dem VB-Compiler "bemuttert". Der wischt halt hinter einem her. Bestes Beispiel ist die Standard Einstellung Option Strict Off, wo ich genau so argumentieren könnte, warum man das denn wohl einschalten sollte. Passiert doch alles für mich und das Ergebnis ist dasselbe.
    Bei C# hat man mehr Verantwortung, muss aber auch dafür Sorge tragen, dass man es richtig macht.
    Es ist nicht so viel wegabstrahiert, sodass man auch mehr machen kann.

    Das hier ist z.B. völlig valider C# Code:

    C#-Quellcode

    1. public unsafe void(byte* ptr, int size) {
    2. while (ptr < ptr + size) {
    3. *ptr = *ptr & ptr;
    4. ptr++;
    5. }
    6. }


    Ist jetzt ein total unsinniges Beispiel, ist mir klar, allerdings kann das VB gar nicht.

    Haudruferzappeltnoch schrieb:

    Das mit den diffs hab ich leider nicht verstanden, ich sehe da nur einen Code.


    Huch. Da ist mir wohl ein Fehler passiert...
    vb_cs_debug.diff.txt

    Anbei noch die zwei MSIL-Dateien aus VB und CS:
    csdebug.txt
    vbdebug.txt
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.

    siycah schrieb:

    Natürlich kann und muss man das.

    Haudruferzappeltnoch schrieb:Wenn zwei verschiedene Codes in Hochsprache zum selben Ergebnis führen

    Wenn ich dreimal rechts fahre, fahre ich auch wieder links. Das Ergebnis ist das selbe, aber der Weg ein Anderer.
    Du schreibst zwar das Gegenteil zu dem was ich geschrieben habe, aber bei der Begründung komme ich nicht hinterher.

    Bei meinem Argument gehts in keinster Weise um den vb-compiler oder um eine bestimmte Hochsprache. Auch wenn vb nicht existieren würde, ist was ich schrieb, das was ich meine.

    Der Compiler Jeder Compiler muss aus dreimal rechts einmal links machen. Wenn er das nicht tut, ist das ein Fehler, den man ausbessern könnte (nicht sollte, weil das ja auch immer ein Kosten/Nutzen Thema ist).
    Das gilt für if - switch in c#
    Das gilt für select - if in vb
    Das gilt nicht für switch - if in c

    Haudruferzappeltnoch schrieb:

    Auch wenn vb nicht existieren würde, ist was ich schrieb, das was ich meine.

    Ahh, entschuldige. Das habe ich so nicht verstanden.

    Haudruferzappeltnoch schrieb:

    Jeder Compiler muss aus dreimal rechts einmal links machen.

    Das siehst du leider falsch. Ich kann den Gedanken aber verstehen und glaube mir, ich habe schon einige Male den GNU Compiler austricksen müssen, damit er das tut, was ich will.

    Jede Programmiersprache definiert sich mit einer gedachten Maschine. Und in den Spezifikationen einer jeden Sprache ist das Verhalten dieser Maschine beschrieben.
    Der Compiler muss dafür sorgen, dass das, was du hinschreibst lexikalisch Sinn macht. Wenn das nicht der Fall ist, du also einen syntaktischen Fehler oder UB (undefined behaviour) produzierst, wird der Compiler entweder eine Warnung, eine Notiz oder wenn der Fehler fatal ist, einen Fehler ausspucken.
    Wenn das, was du schreibst Sinn macht (oder ergibt, wie auch immer), dann legt er mit seiner Analyse weiter und kann - sofern aktiviert - Optimierungen vornehmen.

    Paradebeispiel ist in meinem vorherigen Post mit dem C++ Compiler. Ohne Optimierungen, setzt er das genau so um, wie es seine Regeln, Richtlinien und mein Code ihm vorschreiben.
    Lasse ich ihn optimieren, dann hat der Compiler zu großen Teilen die Entscheidungsgewalt, wie die Anweisungen am Ende aussehen.
    Wenn der Compiler aus Gründen der Meinung ist, dass er etwas nicht oder nur wenig optimieren muss, dann wird das einen Grund haben.
    Je nach Sprache, Version und Konfiguration des Compilers.

    Die Grundregel für diese Optimierungen ist, dass das Verhalten am Ende nicht verändert werden darf.
    Selbst wenn der Compiler deinen ganzen Code über'n Haufen wirft und komplett neu implementiert, darf das von dir angestrebte - trotz Fehler - nicht verändert werden.
    Wenn du ganz bewusst dein Auto dreimal nach rechts lenkst, darf dein Auto auf gar keinen Fall vorher entscheiden, dass es einfach links fährt.

    Haudruferzappeltnoch schrieb:

    Wenn er das nicht tut, ist das ein Fehler, den man ausbessern könnte


    Hängt wie bereits gesagt von der Sprache und dem Standard ab. Das ist aber auch ein tiiieefes Loch in das man fällt, wenn man anfängt, sich mit Compilern auseinanderzusetzen.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.
    Da ist dreimal rechts einmal links natürlich ein schlechtes Beispiel. Der Weg ist da ja das Ziel.
    Aber bei if - switch ist das Ziel ein conditional branch und beide erreichen das doch.

    Es gibt sicher einfach nur wenig solcher Beispiele, gerade weil Redundanzen versucht werden zu vermeiden, gerade weil der Compiler eine gute Assembly schreiben soll.
    Ich könnte mir vorstellen, wenn es tausende solcher Redundanzen in Hochsprache gäbe, die auf Assembly Niveau feine Unterschiede aufweisen, welche auf dem Hochsprachelevel nicht mehr nachvollziehbar sind, dann würden alle Programmierer Assembly noch immer selbst tippern. Die Hochsprache würde dann ja nur obskurieren statt einem Arbeit abzunehmen.

    Und die Redundanz-Beispiele, die mir noch einfallen, sind allesamt syntactic sugar. z.b. auto properties

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Haudruferzappeltnoch schrieb:

    Aber bei if - switch ist das Ziel ein conditional branch und beide erreichen das doch.

    Ja, ist ein deutlich schlechtes - aber einfaches - Beispiel. Stimmt natürlich.

    Haudruferzappeltnoch schrieb:

    Es gibt sicher einfach nur wenig solcher Beispiele, gerade weil Redundanzen versucht werden zu vermeiden, gerade weil der Compiler eine gute Assembly schreiben soll.

    Wenn sie redundant wären, gäbe es sie nicht.

    Deshalb optimiert der Compiler ja. Wenn er sieht, dass er etwas besser machen kann, tut er es.

    Haudruferzappeltnoch schrieb:

    Ich könnte mir vorstellen, wenn es tausende solcher Redundanzen in Hochsprache gäbe, die auf Assembly Niveau feine Unterschiede aufweise, welche auf dem Hochsprachelevel nicht mehr nachvollziehbar sind, dann würden alle Programmierer Assembly noch immer selbst tippern. Die Hochsprache würde dann ja nur obskurieren statt einem Arbeit abzunehmen.

    Genau dafür sind Hochsprachen da: sie abstrahieren die Hardware weg.
    Selbst C/++ sind Hochsprachen.

    C ist natürlich archäisch, aber es ist dennoch eine Hochsprache. In seiner Einfachheit ist er allerdings sehr nah an Assembly gebaut.
    Das Problem ist immer, dass Assembly bzw. Compileranweisungen sich stetig weiterentwickeln und man als Normalsterblicher Mensch gar nicht merken kann, was jede Architektur für Eigen- und Feinheiten hat, was natürlich den Einsatz von Hochsprachen nicht zwingend erfordert, aber sinnvoll macht.

    Ich habe meine Beispiele jetzt in modernem x86_64 ASM gehalten. Das ist aber nicht die einzige CPU-Architektur. Es gibt ja noch ARM, Aarch64, x86, POWER, PowerPC, MIPS, etc. Sogar 6502 ASM und die unterscheiden sich deutlich voneinander. Auch dafür sind Compiler und Hochsprachen da, damit Software portabel ist und bleibt.
    Das sind dann auch nur die Anweisungen, aber jede CPU hat ganz eigene Register und Nomenklaturen.

    Folgender C-Code:

    C-Quellcode

    1. #include <stdio.h>
    2. int main() {
    3. printf("Hello, World!\n");
    4. return 0;
    5. }


    Sieht in x86_64 so aus:

    Quellcode

    1. .LC0:
    2. .string "Hello, World!"
    3. main:
    4. push rbp
    5. mov rbp, rsp
    6. mov edi, OFFSET FLAT:.LC0
    7. call puts
    8. mov eax, 0
    9. pop rbp
    10. ret


    In Loongarch64 so:

    Quellcode

    1. .LC0:
    2. .ascii "Hello, World!\000"
    3. main:
    4. addi.d $r3,$r3,-16
    5. st.d $r1,$r3,8
    6. stptr.d $r22,$r3,0
    7. addi.d $r22,$r3,16
    8. la.local $r4,.LC0
    9. bl %plt(puts)
    10. or $r12,$r0,$r0
    11. or $r4,$r12,$r0
    12. ld.d $r1,$r3,8
    13. ldptr.d $r22,$r3,0
    14. addi.d $r3,$r3,16
    15. jr $r1


    ARMHF:

    Quellcode

    1. .LC0:
    2. .ascii "Hello, World!\000"
    3. main:
    4. push {r7, lr}
    5. add r7, sp, #0
    6. movw r0, #:lower16:.LC0
    7. movt r0, #:upper16:.LC0
    8. bl puts
    9. movs r3, #0
    10. mov r0, r3
    11. pop {r7, pc}


    usw.

    Sie ähneln sich nur darin, dass sie ASM sind.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.
    Warum konkret ist denn if - switch nicht redundant? Ich denke das ist dann der Kern hier.
    Du hattest in Post 10 gezeigt die Assemblies sehen anders aus. Beides geht aber auf dieselbe CPU-Architektur, diesbezüglich muss der Compiler also erstmal nichts unterscheiden.
    Ich denke du sagst die unterschiedlichen Assemblies begründen, es handele sich um keine Redundanz.
    Ich sage es wäre eine Redundanz und der Compiler macht hier einen Fehler, verschiedene Assemblies auszugeben. Denn der Unterschied ist in c# nicht erfassbar.