Sammelthread: Lernen aus Fehlern

Es gibt 39 Antworten in diesem Thema, welches 4.407 mal aufgerufen wurde. Der letzte Beitrag (20. April 2023 um 18:55) ist von GI-Joe.

  • (Hier sollen typische Fehler, Stolperfallen und Missverständnisse beim Programmieren gesammelt werden:)

    Assembler - Tippfehler

    Code
    LDA #0 ; Der konstante Wert 0 wird in den Akku geladen
    
    vs.
    
    LDA $0 ; Der Wert aus der Speicherstelle 0 wird in den Akku geladen

    Im Akku befindet sich u.U. ein anderer Wert als erwartet, weil sich der Inhalt einer Speicherstelle im Programmverlauf verändern kann.

    • Zeropage-Adressen benutzen, die das Betriebssystem doch ganz bestimmt sowieso nicht braucht!
    • In VIC-Registern Bits ausknipsen, die nach menschlichem Ermessen gar keine Bedeutung haben können.
    • Das x-Register kurz zum Zählen benutzen und dabei vergessen, dass da ja ein wichtiger Pointer drinstand.
    • Und ganz wichtig: Zu wenig Testen, denn woher soll man sonst die Zeit nehmen, das neue Feature einzubauen?

    Bitte melde dich an, um diesen Link zu sehen. - Ratespiel • Bitte melde dich an, um diesen Link zu sehen. - BASIC-Erweiterung • Bitte melde dich an, um diesen Link zu sehen. - Sprite-Editor • Bitte melde dich an, um diesen Link zu sehen. - Zeichensatz-Editor Bitte melde dich an, um diesen Link zu sehen. - 2048 Blöcke

  • Interrupt - Initialisierung

    In manchen, besonders älteren Anleitungen steht folgender Beispielcode:

    (*) In der Zeit zwischen Interruptsperre durch SEI und Ausschalten der CIA-Interrupts kann ein nicht behandelter Timer-Interrupt aber zum Programmabsturz führen.

    Die sicherere Lösung ist eine andere Reihenfolge der Befehle:

    Falls die CIA-Timer die einzigen Interruptquellen sind, können hier SEI und CLI sogar ganz entfallen.

  • Ich habe mit vsCode ein altes PHP-Projekt geöffnet.

    Die Textdateien sind wohl Windows 1252, werden aber als UTF-8 interpretiert.

    Umlaute sehen erstmal nur falsch aus, erst beim Speichern sind sie dann wirklich kaputt.

    Über die Statusleiste kann man nach dem Öffnen die Kodierung ändern.

    Würde mich auch nicht wundern, wenn es irgendwo eine Option für den Zweck gibt.

  • Die Textdateien sind wohl Windows 1252, werden aber als UTF-8 interpretiert.

    Das ist... seltsam. Die kompliziertere Kodierung bei UTF-8 gegenüber 1252 oder ISO o.ä. hat nämlich auch einen großen Vorteil: Man kann sofort erkennen, dass eine Datei nicht in UTF-8 kodiert ist, denn jeder einzelne Umlaut in 1252- oder ISO-Kodierung verletzt die UTF-8-Kodierung. Es ist also sehr einfach, direkt nach dem Laden eine entsprechende Meldung anzuzeigen.

    Yes, I'm the guy responsible for the Bitte melde dich an, um diesen Link zu sehen. cross assembler. And some Bitte melde dich an, um diesen Link zu sehen..

  • Die Textdateien sind wohl Windows 1252, werden aber als UTF-8 interpretiert.

    Das ist... seltsam. Die kompliziertere Kodierung bei UTF-8 gegenüber 1252 oder ISO o.ä. hat nämlich auch einen großen Vorteil: Man kann sofort erkennen, dass eine Datei nicht in UTF-8 kodiert ist, denn jeder einzelne Umlaut in 1252- oder ISO-Kodierung verletzt die UTF-8-Kodierung. Es ist also sehr einfach, direkt nach dem Laden eine entsprechende Meldung anzuzeigen.

    Vielleicht gibt es da ja auch eine Option irgendwo...

  • Bei mir persönlich "beliebter" Fallstrick: In einer ISR, die eh nur den Akku benutzt, auch nur den sichern, z.B. so:

    Code
    isr:    sta    rest_a+1
            [...]
    rest_a: lda    #$ff
            rti

    Später refactorn, in die ISR muss irgendein JSR rein. Dann ne Stunde debuggen, warum ganz ganz komische Dinge passieren. Dann X und Y auch sichern :biggrin:

  • Code
    isr:    sta    rest_a+1
            [...]
    rest_a: lda    #$ff
            rti

    Um event. Fehler bei selbstmodifizierendem Code zu vermeiden, kann man Lables wie rest_a: auch so definieren:

    Code
    isr:    sta    rest_a
            [...]
    rest_a: * + 1
            lda    #$ff
            rti
  • ogd, DAVON bin ich wieder abgekommen, weil es meiner Meinung nach den Code eher hässlich aufbläht/auseinanderreißt ohne einen echten Mehrwert zu bieten. Aber jeder wie er mag :smile: edit: btw, in deinem Beispiel sollte es = statt : sein um das label direkt für das Argument zu definieren :wink:

    2 Mal editiert, zuletzt von Zirias/Excess (7. Februar 2023 um 14:52)

  • Entprellte Joystickabfrage in einem schnellen Loop:

    Funktioniert astrein im Emulator, aber auf echter Hardware wird nicht gescheit entprellt, weil der Joystick beim Tastendruck etliche Millisekunden lang auf der Leitung herumzappelt. Daher die Joystickabfrage am besten in den IRQ packen, nach einem Frame (ca. 20ms) ist die Zappelei auf jeden Fall vorüber.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

    Einmal editiert, zuletzt von Claus (7. Februar 2023 um 15:35)

  • Ganz beliebt: das 9. Bit für die Rasterzeile beim Setzen des Rasterinterrupts ignorieren. Je nach zufälligem Inhalt wird dann der Interrupt nie getriggert, weil es die Zeile mit gesetztem 9. Bit gar nicht gibt.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • Sprites aktiviert lassen bei Kernal Load/Save.

    ────────────────────────────────────────────────────────────
    Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen.
    ────────────────────────────────────────────────────────────

  • DAVON bin ich wieder abgekommen, weil es meiner Meinung nach den Code eher hässlich aufbläht/auseinanderreißt ohne einen echten Mehrwert zu bieten.

    Hässlich ist es auf jeden Fall, aber es bietet durchaus einen Mehrwert: Die Referenzen sehen so aus wie sonst auch, d.h. "+1" kennzeichnet einen Zugriff auf das High-Byte. Nimmt man stattdessen das Label vor dem Befehl, wird das Lowbyte mit "+1" und das Highbyte mit "+2" referenziert.

    Dass "+1" in meinen Sources immer die gleiche Bedeutung hat, ist mir die Hässlichheit der Labeldefinition wert.

    EDIT: Um on-topic zu bleiben: Ein beliebter vermeidbarer Fehler ist, mit "+1" bei manchen Variablen das Low- und bei manchen das High-Byte zu referenzieren. :D

    Yes, I'm the guy responsible for the Bitte melde dich an, um diesen Link zu sehen. cross assembler. And some Bitte melde dich an, um diesen Link zu sehen..

  • EDIT: Um on-topic zu bleiben: Ein beliebter vermeidbarer Fehler ist, mit "+1" bei manchen Variablen das Low- und bei manchen das High-Byte zu referenzieren. :D

    Da bin ich ja der Meinung: IMMER little-endian, ausnahmslos :biggrin: Die CPU selbst macht das so. BASIC macht es wohl an ein paar wenigen Stellen big-endian, schlimm genug :biggrin:

  • Da bin ich ja der Meinung: IMMER little-endian, ausnahmslos :biggrin:

    Na klar, ich bezog mich da nur auf die selfmod-Label.

    Yes, I'm the guy responsible for the Bitte melde dich an, um diesen Link zu sehen. cross assembler. And some Bitte melde dich an, um diesen Link zu sehen..

  • EDIT: Um on-topic zu bleiben: Ein beliebter vermeidbarer Fehler ist, mit "+1" bei manchen Variablen das Low- und bei manchen das High-Byte zu referenzieren. :D

    Da bin ich ja der Meinung: IMMER little-endian, ausnahmslos :biggrin: Die CPU selbst macht das so. BASIC macht es wohl an ein paar wenigen Stellen big-endian, schlimm genug :biggrin:

    Auch Rodnay Zaks empfielt das in seinem bekannten Buch "Programmierung des 6502":

    Zitat

    In der Tat werden Adressen durch den 6502 gerade umgekehrt gespeichert. Zuerst kommt der niederwertige Teil, in der nächsten Speicherstelle dann der höherwertige. Um für Daten und Adresse dieselbe Vereinbarung zu haben, ist zu empfehlen, auch bei Daten die höherwertige Hälfte nach der niederwertigen Hälfte im Speicher zu halten.

    Also gilt auch hier: Konsistenz immer vor Schönheit!

  • Konsistenz immer vor Schönheit!

    Wobei das für mich bei DEM Thema eigentlich dasselbe ist :nixwiss: ... ich hatte vor kurzem schon in nem anderen Thread mit Hilfe unseres arabischen Zahlensystems begründet, warum eh NUR little-endian Sinn ergibt :thumbsup: Aber ok, da stochere ich jetzt quasi in dem Ur-Flamewar aus Gulliver :D

  • Noch einer "On-Topic": Implizite Annahmen treffen, immer sehr beliebt. Wenn die dann brechen geht die große Sucherei los.

    Ein Beispiel speziell bei der C64-Programmierung: Man hat ein Cartridge mit eigenem Bootcode (oder faked das im RAM). Alles was der KERNAL tut, bevor er das anspringt, ist Stackpointer initialisieren und decimal mode deaktivieren. Und doch, nach einem RESET kann man sich ja darauf verlassen, dass z.B. keine Interrupts auftreten.

    Richtig? Richtig! Nur, was wenn man die boot-routine selbst aktiv anspringen will für einen programmatischen Restart? Dann sind vielleicht DOCH interrupts aktiv :biggrin: Hat mich auch schon ein wenig debugging-Zeit gekostet :smile:

  • Und noch einer, bei dem ich mir aber nicht so ganz sicher bin ob das stimmt, weil ich das nur in VICE gesehen habe (in Ermangelung echter NTSC Hardware): Auf NTSC ist Rasterline 0 NICHT im vblank, sondern irgendwo am unteren Rand des sichtbaren Bildschirms :silly:

  • Manchmal muss man ein Programm nur eine Weile liegen lassen. Danach hat man wieder einen frischen Blick und entdeckt Fehler, über die man vorher XMal drübergeguckt hat.

    Ich hatte mal ein Multitasking mit BRK aufgebaut.

    Die Erkennung in der IRQ-Routine: Wenn kein VIC-Irq und kein CIA-IRQ, dann war es BRK.

    Das ist leider falsch. Einfach mal 20 Jahre liegen lassen, und schon ist der Fehler gefunden.