[Suchen Autor für:] Bugs bei denen man lange sitzt



  • Artchi schrieb:

    Tja, und ich habe ewig gesucht, woran das Problem liegen könnte. Nur nicht im switch-case-Konstrukt!

    single-step im debugger, dann hätteste es leicht gefunden 😉

    Artchi schrieb:

    Was habe ich daraus gelernt? zu jedem case überprüfe ich heute instinktiv ob ich auch ein passendes break habe. Sobald ich case schreibe, hau ich sofort ein break rein. Egal was kommt! Das break kann ich immer noch weg nehmen, wenn ich es doch nicht brauche.

    ich würde aber noch einen kommentar hinschreiben,
    mindestens: */* Intentionally no BREAK here /
    sonst baut man später noch ein break ein, weil man meint es vergessen zu haben. 😃
    edit: zu laaahhhhm 😞

    topic: am schlimmsten finde ich bugs, die man nicht selber fabriziert hat, z.b. falsch funktionierende library-funktionen und dergleichen...
    🙂



  • Ich werde immer mal wiede rausgelacht, weil ich IMMER Klammern setze.
    Ich habe grundsätzlich zu viele Klammern... egal ob () oder {}

    Allerdings ist mir sowas lieber als die Sucherei, warum das immer Meldung macht und nicht nur, wenn x, was es soll:

    if (x == 3)
        tuwas();
        MachMeldung();
    tuwasanderes();
    

    Und: Schöner Fehler, den ich grade aus Versehen drin hatte:

    if (x = 3)
        tuwas();
        MachMeldung();
    tuwasanderes();
    

    ...für runde Klammern fällt mir grade nix ein...



  • estartu schrieb:

    Und: Schöner Fehler, den ich grade aus Versehen drin hatte:

    if (x = 3)
        tuwas();
    

    schreib das nächste mal if (3==x)
    🙂



  • Das finde ich persönlich echt häßlich... auch wenn's gegen sowas hilft.



  • pale dog schrieb:

    estartu schrieb:

    Und: Schöner Fehler, den ich grade aus Versehen drin hatte:

    if (x = 3)
        tuwas();
    

    schreib das nächste mal if (3==x)
    🙂

    Wie schon jemand weiter oben sagte: Einige Fehler lassen sich durch Konventionen vermeiden.

    Bei mir fangen alle Member mit m_ und alle Parameter mit f_ an... schon kann mir das eine genannte Beispiel nicht passieren. 😉



  • Jester schrieb:

    Artchi schrieb:

    Was habe ich daraus gelernt? zu jedem case überprüfe ich heute instinktiv ob ich auch ein passendes break habe. Sobald ich case schreibe, hau ich sofort ein break rein. Egal was kommt!

    Genau das meine ich, sowas gehört in sonen Text auf jeden Fall mit rein.

    Allerdings sollte es begründet sein und da helfen nun einmal konkrete Beispiele damit das ganze nicht in der Luft hängt und man überzeugend wirkt. Man braucht also beides.

    Der erste Fehler hat bei mir dazu geführt, dass ich sobald es unerklärliche Abstürze gibt in jeden Copykonstruktor ein

    assert(&other != this);
    

    rein tue. Hilft oft den Fehler zu finden. Einfach mit dem Debugger warten bis der assert fliegt dann noch einmal kurz einen Stacktrace und der Fehler ist behoben.

    Artchi schrieb:

    Kann überhaupt ein einziger Autor solch eine Liste aufschreiben? Man, der muß ja echt Probleme gehabt haben.

    Natürlich kann eine solche Liste nicht komplett sein allerdings geht die Fehlersuche schneller je mehr mögliche Fehler man kennt.

    ...für runde Klammern fällt mir grade nix ein...

    1 << 2&6 schreiben wo 1 << (2&6) gemeint ist. Bei solchen Operatoren setze ich auch immer Klammern.

    Mir schwebte eher ein Artikel vor welcher ungewöhliche Fehler darstellt und erklärt also eher ein Kuriositätenkabinett als ein Artikel der Tipps gibt wie man Fehler verhindert. Wer kannte Bug Nummer 3 im ersten Post bevor er hier gelesen hat? Beinahe alle (alle?) Bücher sagen, dass private dazu dient die Implementation zu verstecken, also wieso sollte es einen Einfluss auf abgeleitete Klassen haben? Ich glaube da wären viele erstaunt zu sehen, dass diese Kapselung doch nicht immer so ganz dicht ist.

    Das Beispiel mit if(a = 3) ist natürlich ein sehr häufiger der glaub ich bereits von jedem mindestens einmal gemacht wurde. Ein Weg ihn zuverlässig zu verhindern wäre sicher interessant hat aber in einem Kuriositätenkabinett nichts zu suchen da er allgemein bekannt ist.

    Der Nutzen eines Artikels welcher sich mit der Fehlersuche allgemein beschäftigt sehe ich auch allerdings wäre das glaub ich ein anderer. Beispiel #3 hätte in dem nichts zu Suchen da es einen, in meinen Augen, wenig praxisnaher Bug ist.

    Das wären dann schon zwei Vorschläge. 🙂



  • int Koordinate[_SIZE]={0};
    
    // später bei der Eingabe:
    
    if( Eingabe < 0 || Eingabe > _SIZE ) WirfFehlerMeldung();
    else SchreibInsArray();
    

    Und ich such eine halbe Stunde, warum da ständig was über die Arraygrenzen rausfliegt...

    Toffi



  • was gibt das aus?

    int a = 1;
    printf ("%d-%d-%d\n", a++, a++, a);
    

    1-2-3 oder was anderes?
    🙂



  • pale dog schrieb:

    was gibt das aus?

    int a = 1;
    printf ("%d-%d-%d\n", a++, a++, a);
    

    1-2-3 oder was anderes?
    🙂

    Und wieder ein klassisches Beispiel für undefiniertes Verhalten - dort könnte nahezu alles von 1-1-1 bis 3-3-3 hinten rauskommen (OK, mir fällt gerade keine Auswertereihenfolge ein, die letzteres produziert), je nachdem in welcher Reihenfolge der printf()-Ausdruck ausgewertet wird.



  • Ben04 schrieb:

    Jester schrieb:

    Genau das meine ich, sowas gehört in sonen Text auf jeden Fall mit rein.

    Allerdings sollte es begründet sein und da helfen nun einmal konkrete Beispiele damit das ganze nicht in der Luft hängt und man überzeugend wirkt. Man braucht also beides.

    Stimmst Du mir da zu? Ich verstehe nicht was Du damit sagen willst, klingt irgendwie als wolltest Du mir widersprechen, wobei ich da den Punkt nicht sehe. 😕



  • Wollte eher verdeutlichen/betonen, dass beide Teile wichtig sind, widersprechen wollte ich eigentlich nicht. Das "Allerdings" war fehl am Platz.



  • Ich hatte heute was nettes:

    class Basis
    {
    public:
        virtual void tuwas(int bla);
    };
    
    class Extended : public Basis
    {
    public:
        virtual void tuwas(int bla);
    };
    

    Und auf der "obersten" Ebene gibt es zig abgeleitete Klassen wie z.b.

    class Spezial : public Extended
    {
    public:
        virtual void tuwas(int bla);
    };
    

    Und irgendwo ruft man das dann über die Basisklasse auf:

    Spezial blub;
    Basis* pBasis = &blub;
    pBasis->tuwas(3);
    

    Soweit, alles prima. 👍

    Nun funktioniert der Code monatelang super.
    Man muss, wie das so ist immer wieder hier und da was anpassen.
    Und dann mach man sowas:

    class Spezial : public Extended
    {
    public:
        virtual void tuwas(int bla, bool blub);
    };
    

    Und schon tut der Aufruf nicht mehr, was man von ihm gewohnt ist. 😮
    Weil nämlich nicht wie erwartet Spezial::tuwas aufgerufen wird sondern Extended::tuwas. ⚠

    Liegt eine solche Änderung auch noch mehrere Tage zurück und war wegen einer ganz anderen Funktion als da wo der Fehler auftritt, sucht man sich dumm und dusselig. 🙄



  • Hallo

    ja mit dem virtual kann man tolle Fehler machen, vor allem wenn es vom Konstruktor oder Destruktor aufgerufen wird

    class Base
    {
      Base()
      {
        Build();
      }
      virtual void Build()
      {
        std::cout << "Base::Build" << std::endl;
      }
    };
    
    class Child : public Base
    {
      Child() : Base()
      {
      }
      virtual void Build()
      {
        Base::Build();
        std::cout << "Child::Build" << std::endl;
      }  
    };
    ...
    Child test;
    

    Man wundert sich erstmal warum nur Base::Build aufgerufen wird...
    Virtuelle Funktionen sollten niemals die Arbeit von Konstruktor und Destruktor übernehmen.

    bis bald
    akari



  • Es würde durchaus Hilfreich sein wenn man zu den geposteten Fehler mal Informationen liefert.

    Wenn man vorher / nachher zeigt, wird der eigentliche Fehler nur denen klar, die danach nicht lange suchen würden. Diese Sammlung soll ja wohl weniger eine Auflistung von pralerei sein sondern anderen Helfen solche Fehler zu vermeiden. Und da ist es unumgänglich das man erläutert, wo das Problem im gezeigten Code besteht.



  • class A{
    public:
    virtual void foo()const;
    };
    
    class B:public A{
    public:
    virtual void foo();
    };
    
    //...
    const A*a=new B;
    a->foo(); // Ruft A::foo und nicht B::foo auf.
    


  • Meines Erachtens wäre etwas zu Kopierkonstruktor und überladenem Zuweisungsoperator bei Klassen mit Zeigern als Membern noch nützlich... Da passiert es auch sehr schnell, dass man die Übersicht verliert.
    Oder eventuell auch sonstige, häufige Zugriffsverweigerungen bei der Arbeit mit Zeigern (ich weiss jetzt gerade keine guten Beispiele). Oder Funktionen, die Referenzen auf lokale Variabeln zurückgeben, und solche Sachen...



  • "Nur triviale Programme sind völlig bugfrei zu schreiben!" Möglichkeiten für Fehler, die der Compiler und der Linker nicht erkennen, gibt es viele. Dann heisst es Debuggen und Suchen. Einen Artikel für "alles" zu schreiben, erscheint mir nahezu unmöglich. Ich hatte zu Zeiten ohne Debugger in einer Schleife den Fehler, die Laufvariable i mit der Konstante 1 zu vertauschen. Das Programm lief, nur lieferte es Schrott. Ich habe lange in den Sourcelisten gesucht und nichts gefunden. Ein Arbeitskollege wurde dann fündig. Folgerung: Wir sollten besser über Regeln zur sauberen wartungsfreundlichen Programmierung nachdenken, die wir anderen mitteilen können. Hierzu könnte ich etwas beitragen aus meinen persönlichen Programmierstil.



  • berniebutt schrieb:

    Ich hatte zu Zeiten ohne Debugger in einer Schleife den Fehler, die Laufvariable i mit der Konstante 1 zu vertauschen.

    hast du die 1 in der schleife mit einer anderer konstanten verglichen? in dem fall sollte ein guter compiler warnen, dass der vergleich immer true oder false ergibt und daher rausfliegt.

    berniebutt schrieb:

    Wir sollten besser über Regeln zur sauberen wartungsfreundlichen Programmierung nachdenken, die wir anderen mitteilen können.

    genau. hier kommt schon mal eine regel: man wähle im editor immer einen zeichensatz, bei dem auch ein halbblinder nichts verwechseln kann.
    🙂



  • Das Thema "Sauberes wartungsfreundliches Programmieren" lässt sich einfach nicht mit einem einzelnen Artikel im Magazin abhandeln. Dazu ist die Aufgabe zu komplex! Es gibt aber durchaus hilfreiche Regeln, die offen diskutiert werden können.



  • Ja, dann immer her damit. Auch wenn sich noch kein Autor gemeldet hat, der Thread ist auch so schon interessant. 🙂


Anmelden zum Antworten