Kommentare - wie, was, wo, wann



  • Hallo,

    da ich in einem kleinen Code-Wettbewerb kürzlich massiven Punkteabzug bekommen habe, weil mein Code nur sehr spärlich (bis gar nicht) kommentiert wurde, würde ich gerne wissen, wie ihr das handhabt und was ihr sonst so für Tipps habt.
    Gibt es in C und C++ Kreisen irgendwelche Konventionen, von denen ich wissen sollte?
    Kommentiert ihr im Header zum Beispiel nur die Schnittstelle oder kommentiert ihr dann auch noch die Source Datei *.cpp?
    Ich dachte, dass gute Variablennamen vielleicht ausreichen (für diese wurde ich sogar gelobt), aber dem ist anscheinend nicht so. Gibt es irgendwelche Regeln, an denen ich mich vielleicht orientieren kann? Meine eigenen Gedanken erscheinen mir natürlich immer logisch und jeden Befehl zu kommentieren ist vermutlich auch übertrieben.

    Vielen Dank schon einmal für eure Hilfe!



  • Schau dir doch mal die Source Dateien eines großen Open Source Projektes. Wie es dort gehandhabt wird hilft dir vielleicht weiter.



  • Tatsächlich eine gute Idee, darauf bin ich gar nicht gekommen.
    Hast du da irgendein empfehlenswertes Projekt? Sollte vielleicht natürlich nicht zu groß sein. 😉



  • Groß, aber sehr gut: Postgresql, OpenBSD.



  • Jede Funktion sollte kommentiert werden.
    Wichtig ist, was sie tut, was die Parameter bedeuten, welche Vorbedingungen die Funktion erfordert und was die Funktion zurückliefert.
    Ebenso gehört dazu, welche Expcetion sie wirft und warum, sowie welche Seiteneffekte auftreten können.

    Diese Art von Kommentierung gehört insbesondere bei nicht privaten Funktionen zur Dokumentation. Also z.B. für Doxygen usw..
    Für Doxygen sollte man die Kommentare also entsprechend Kennzeichnen.

    Innerhalb der Funktion kann man dann noch Kommentare für Variablen angeben, vor allem dann, wenn die Namen nicht selbsterklärend genug sind.
    Ebenso kann man noch komplexere Codeabschnitte kommentieren, damit klar wird, was dieser Codeabschnitt in seiner Gesamtheit tut.
    Hast du z.B. eine Schleife, dann kannst du kurz einen groben Überblick geben, was in der Schleife gemacht wird. Du sollst aber nicht Schritt für Schritt erklären, wie genau all das in der Schleife funktioniert.

    Das gleiche gilt für eine Switch Anweisung oder If kaskade.
    So etwas kommentiert man grob, damit man sich nicht in diesen Codeabschnitt Schritt für Schritt reinfrimmeln muss.

    Jeden Befehl einzeln zu kommentieren muss man gewiss nicht und soll man auch nicht.

    Versuch dich einfach in dein Gegenüber zu versetzen, der den Code zum ersten mal sieht und jetzt einen groben Überblick bekommen soll, ohne dass er jetzt Zeile für Zeile, Befehl für Befehl des Codes einzeln durchgehen muss.

    Im Zweifelsfall kommentiert man lieber mehr als zu wenig.



  • Noch eine Ergänzung

    Versuche den Code in Blöcke zu struktuieren und gib dann ein grobes Kommentar, was der Block macht.


  • Mod

    Das ist eindeutig eine Übungsgeschichte, man braucht ein wenig "Gefühl" für das passende (oder: hängt vom Zusammenhang ab) und man kann das ganze auch diskutieren, da uneindeutig und verschiedene Geschmacksrichtungen.

    Vielleicht hilft es auch, mal genau das Gegenteil zu machen:
    https://bellard.org/otcc/
    oder die Internetseiten zu "How To Write Unmainainable Code"

    Besser aber, irgendwie, von den besten abgucken.
    (z.B. viele Module)

    Und, zu kleinen Erleichterung im Chaos des Lebens: drei Karten mit Totenköpfen drauf und als Untertext:

    1. keine Dokumentation
    2. nur teilweise dokumentiert
    3. schlecht dokumentiert
      (diese nette Aufteilung wurde in dem Buch "The Rootkit Arsenal" von Bill Blunden angesprochen.)

    Die Lage ist hoffnungslos, aber nicht ernst:
    https://magazin.c-plusplus.net/artikel/(Humor) Klingonische Softwareentwickler



  • Danke für die vielen Anregungen.

    computertrolls schrieb:

    Versuche den Code in Blöcke zu struktuieren und gib dann ein grobes Kommentar, was der Block macht.

    Wenn ich meinen Code in Blöcke unterteile, dann zerstöre ich damit nur meine Gültigkeitsbereiche. Oder meinst du, dass ich Funktionen benutzen soll? Das ist nämlich nicht das Problem.

    Dann hätte ich noch eine Frage: kommentiert ihr am Ende der Zeile oder am Anfang? Soll ich alles in ekne Zeile quetschen, Zeilenumbrüche einfügen, wenn es zu viel wird, oder Kommentare finden, die in eine Zeile paasen?
    Das mit den zu langen Zeilen habe ich auch im Code als Problem bei mir,z.B. bei Initialisiererlisten im CTOR. Aber Zeilenumbrüche aind irgendwie auch hässlich. Wie macht ihr das da?

    Das mit den Schleifen ist auf jeden Fall schon einmal ein guter Tipp, danke.
    Als letzte Frage noch: erst alles fertig coden und dann kommentieren oder gleichzeitig kommentieren? Das Kommentieren lenkt mich nämlich irgendwie immer vom eigentlichen coden ab.

    Danke!



  • bls-comm schrieb:

    Danke für die vielen Anregungen.

    computertrolls schrieb:

    Versuche den Code in Blöcke zu struktuieren und gib dann ein grobes Kommentar, was der Block macht.

    Wenn ich meinen Code in Blöcke unterteile, dann zerstöre ich damit nur meine Gültigkeitsbereiche. Oder meinst du, dass ich Funktionen benutzen soll? Das ist nämlich nicht das Problem.

    Ich meine damit nicht, dass du den Code umschreiben sollst, so dass er zu Blöcken wird, sondern dass du in der Quellcodedatei, die ja im Prinzip eine reine Textdatei ist, den Code so anordnest, dass er strukturiert vorliegt.
    Das ist also eine reine Kommentar- bzw. Anordnungssache, der eigentliche Code ändert sich dadurch nicht.

    Eine while Schleife kann bpsw. so einen Block sein, am Kopf machst du dann ein Kommentar.
    Genauso auch eben ein switch Block.

    Aber auch komplexere Dinge, in denen irgendwas passiert, aber das man nicht in eine Funktion auslagert.

    Als Analogie, guck dir dieses Kommentar hier an, ich verwende Absätze. Würdest du das Kommentar auf Papier ausdrucken, dann könntest du zu jedem Absatz am Rand eine kurzes Kommentar machen, das kurz und vereinfach sagt, was im Absatz erzählt wird.
    Damit ist der Absatz ein Block, der Text ändert sich dadurch aber nicht, es ist nur die Anordnung des Textbildes.
    Und so kann man das auch bei Code machen.

    Auch da kann man Code schön zusammenfassen und dann den Block kommentieren.

    Dann hätte ich noch eine Frage: kommentiert ihr am Ende der Zeile oder am Anfang?

    Kommentare für die Doku einer Funktion gehören vor den Funktionskopf in eine oder mehrere eigene Zeilen.

    Reine Implementierungskommentare kommen je nach Länge des Kommentars in eigene Zeilen oder hinten dran, wenn es kurz in wenigen Worten kommentiert werden kann.
    Bei Variablen reicht es meist, wenn man einfach hinten dran kurz was hinschreibt.

    Da wirst du schon noch ein Gefühl dafür entwickeln.

    Das mit den zu langen Zeilen habe ich auch im Code als Problem bei mir,z.B. bei Initialisiererlisten im CTOR. Aber Zeilenumbrüche aind irgendwie auch hässlich. Wie macht ihr das da?

    Früher hat man Quellcode noch in Editoren und IDEs geschrieben, die im ASCII Textmodus den Code darstellten.
    Der Textmodus hatte eine übliche Spaltenlänge von 80 Zeichen, höhere Modi boten eine Spaltenlänge von 132 Zeichen.
    Auch Drucker hatten beim Druck mit dieser Spaltenlänge kein Problem, aber alles was darüberhinaus ging, konnte abgeschnitten werden.
    Und auf dem Bildschirm horizontal scrollen wollte auch keiner.

    Deswegen hat man den Code an dieser Spaltenlänge orientiert.
    Heute können gute Editoren eine Linie an dieser Spaltenlänge anzeigen, so das
    man sich beim Schreiben daran orientieren kann.
    Natürlich kann man heute wesentlich längere Zeilen verwenden, bei Java macht
    das sogar Sinn, weil in eine Spaltenlänge von 80 Zeichen da eh fast nichts reinpasst, aber wenn du dir selbst so eine Spaltenbreite definierst, sagen wir mal 132 Zeichen, dann kannst du dich an dieser orientieren.

    Passt das Kommentar noch bei deiner definierte Spaltenbreite am Ende einer Zeile hin, dann kommentiere am Ende der Zeile, wenn nicht, dann setze das Kommentar in eine neue Zeile.

    Für neue Zeilen solltest du übrigens folgenden Kommentar Operator verwenden /* und */.
    Und für Kommentare an Zeilenende, den doppelten Slash, also //.

    Als letzte Frage noch: erst alles fertig coden und dann kommentieren oder gleichzeitig kommentieren?

    Gleichzeitig, wobei du das recht locker nehmen kannst.
    Aber wenn du schon 3 h am Code tippen bist und schon jede Menge Code erstellt hast, dann wird es höchste Zeit, auch mal über das bereits geschriebene zu sinieren und Kommentare hinzusetzen.
    Vieles kann man aber auch schon einfach am Anfang hinzuschreiben.
    Definiere ich z.b. eine Variable, dann setze ich das Kommentar, sofern notwendig, gleich dahinter.
    Bei Kommentaren zu Funktionen, als an deren Köpfe reicht ein kurzer Hinweis, sofern überhaupt erforderlich, denn für die Doku musst du da sowieso noch einmal drüber schauen.
    Dann sollte das schon ordentlich kommentiert sein.

    Das Kommentieren lenkt mich nämlich irgendwie immer vom eigentlichen coden ab.

    Dann machst du dir über das Kommentieren zu viele Gedanken.

    Mein Vorschlag, teile den Code ein, wie oben beschrieben und dann kommentiere immer dann, wenn ein funktionaler Abschnitt fertig ist.



  • bls-comm schrieb:

    Als letzte Frage noch: erst alles fertig coden und dann kommentieren oder gleichzeitig kommentieren? Das Kommentieren lenkt mich nämlich irgendwie immer vom eigentlichen coden ab.

    Dazu noch etwas.

    Denke daran was der Sinn des Kommentierens ist.

    Man kommentiert
    A) um eine Dokumentation (Stichwort Doxygen) für die nicht privaten Funktionen, Methoden, Attribute usw. zu haben
    und
    😎 einem Dritten die Möglichkeit zu bieten, den Code kurz zu überfliegen und die Kommntare so zu schreiben, dass er anhand der Kommentare weiß, was da grob passiert. Er sich also in den Code reinfinden kann.
    und
    C) du selbst, nach ein paar Tagen, Wochen, Monate, Jahre etc. wieder schnell in den Code reinfinden kannst.

    Das bedeutet also.
    Programmierst du deinen Code an einem Tag, dann wirst du wahrscheinlich den ganzen Tag kaum ein Kommentar benötigen, weil du dich noch daran erinnern kannst, wo was wie liegt.
    Legst du den Code dann aber mal übers Wochenende zur Seite und kommst am Montag wieder, dann wäre es schon sinnvoll, wenn er kommentiert wäre, damit du selbst dich wieder in diesen gut einfinden kannst.

    So ist das zu sehen, daran solltest du dich orientieren. Mit der Zeit entwickelt man dafür ein Gefühl.

    Und beachte bitte, dass nicht jeder Befehl kommentiert werden muss.
    So etwas z.B.:

    std::cout << "Hallo Welt! << endl; // Dieser Befehl gibt Hallo Welt! auf dem Bildschirm aus.
    

    kommentiert man natürlich nicht.
    So etwas ist selbsterklärend, wer C++ kann, der weiß was std::cout macht.

    Anders kann es z.B. bei so etwas aussehen:

    std::cout << datapoint << endl; // Ausgabe des Messwerts
    

    Wenn man jetzt nach nem Jahr wieder in den Code schaut, dann wäre ohne Kommentar
    nicht klar, was da ausgegeben wird, man müsste schließlich erst einmal wissen, was die Variable datapoint darstellt.
    Hier kann dann ein kurzes Kommentar helfen, in obigem Fall wird ein Messwert ausgegeben und schon ist klar was los ist.
    Wer es dann genauer wissen will, kann tiefer in den Code reinknien und z.b. noch bei datapoint nachschauen, aber grob weiß er schonmal, dass es hier um einen Messwert geht.

    Natürlich könnte man auch die Variable datapoint selbst messwert nennen, dann kann man das Kommentar weglassen, was man natürlich dann auch tun würde, aber vielleicht ist im gegebenen Fall die Benennung der Variablen etwas komplexer, so dass es mit solchen Variablennamen nicht geht, spätestens dann kann ein kurzes Kommentar hilfreich sein.

    Und wenn du eine Tabelle ausgibst, und die Ausgabe der Datenpunkte in Spalten und Zeilenform mithilfe einer for Schleife aufbaust, dann kommentierst du natürlich nicht den cout Befehl, sondern setzt das Kommentar am Anfang der for Schleife oder setzt das ganze in eine extra Funktion und dann schreibst du als Kommentar vor der for Schleife bzw. vor dem Funktionskopf hin, dass hier die Tabelle mit den Messwerten ausgegeben wird.

    Aber wie schon gesagt, mit der Zeit entwickelst du ein Gefühl dafür.



  • computertrolls schrieb:

    Deswegen hat man den Code an dieser Spaltenlänge orientiert.
    Heute können gute Editoren eine Linie an dieser Spaltenlänge anzeigen, so das
    man sich beim Schreiben daran orientieren kann.
    Natürlich kann man heute wesentlich längere Zeilen verwenden, bei Java macht
    das sogar Sinn, weil in eine Spaltenlänge von 80 Zeichen da eh fast nichts reinpasst, aber wenn du dir selbst so eine Spaltenbreite definierst, sagen wir mal 132 Zeichen, dann kannst du dich an dieser orientieren.

    Passt das Kommentar noch bei deiner definierte Spaltenbreite am Ende einer Zeile hin, dann kommentiere am Ende der Zeile, wenn nicht, dann setze das Kommentar in eine neue Zeile.

    Ach noch etwas, für Funktionen und Blockweises kommentieren (denk an die Absätze) sollte man natürlich das Kommentar in eine neue Zeile vor den jeweiligen Block setzen.

    Also bspw:

    Falsch:

    for (int i; i < n; i++){ // Kommentar
      ...
    }
    

    Richtig:

    /* Kommentar */
    for (int i; i < n; i++){ 
      ...
    }
    


  • @computertrolls
    Ist dir fad?



  • hustbaer schrieb:

    @computertrolls
    Ist dir fad?

    Ich bin erkältet und habe generell ein Helfersyndrom.



  • Und ein "ich habe die einzige Wahrheit, wer anderer Meinung als ich ist hat einfach Unrecht" Syndrom.

    Viel was du hier zum Thema Kommentieren schreibst klingt nämlich theoretisch gut, ist praktisch aber Unfug. Bzw. einfach unpraktikabel weil vom Kosten/Nutzen Faktor her nicht vertretbar.



  • Wie gesagt, die Variablennamen sind üblicherweise nicht das Problem. Etwas komplexer als std::cout << sth; sind meine Programme leider doch. 😉
    Aber gerade das mit den Blöcken halte ich für eine gute Idee.
    Hustbär, wie machst du es denn üblicherweise und was würdest du anders machen?



  • @computertrolls:
    Mal aus reinem Interesse:

    Du schreibst ja nicht schlecht oder so, aber das Kommentar hört sich so unfassbar falsch an (ist es ja auch), weshalb mich interessiert aus welcher Region du kommst.
    Ist das Österreich?



  • also ich habe in meinem momentanem projekt drei große funktionen (1000 - 2000 zeilen), die ich nicht aufteilen möchte und da mache ich dann sowas:

    void funk()
    {
         //mach was 1
         {
              struk->data11 = 1;
              struk->data12 = 2;
         }
    
         //mach was 2
         {
              struk->data21 = 3;
              struk->data22 = 4;
         }
    }
    

    der inhalt der blöcke ist an und für sich selbst erklärend, aber bei visual studio kann ich die blöcke "einklappen", sodass dann nur noch die kommentare da stehen und ich dann sehen kann, wo was gemacht wird.

    ich finde, dass das sehr gut hilft.



  • Das Einklappen kann eigentlich jede gute IDE, sogar manche einfache Editoren wie Kate.
    Nachteil von solchen Blöcken ist allerdings eben, dass die Gültigkeitsbereiche noch einmal neu getrennt werden. Bei solchen großen Funktionen würde ich aber auch für jede Funktion eine eigene Datei verwenden.
    Die Blöcke halte ich leider tatsächlich (zumindest für mich) nicht für die optimale Lösung.



  • Wade1234 schrieb:

    also ich habe in meinem momentanem projekt drei große funktionen (1000 - 2000 zeilen), die ich nicht aufteilen möchte

    Was vermutlich ein Fehler ist.
    Bei uns fangen die Jungs schon zum Sudern an wenn man Files in der Grössenordnung hat. Was ich persönlich jetzt wieder übertrieben finde, 2000 Zeilen sind IMO net Schlimm für ein File. Aber für eine Funktion ... eieiei.

    Kennst du das Method-Object Pattern?



  • bla-comm schrieb:

    Aber gerade das mit den Blöcken halte ich für eine gute Idee.
    Hustbär, wie machst du es denn üblicherweise und was würdest du anders machen?

    Ich kommentiere keine offensichtlichen Dinge, wie

    computertrolls schrieb:

    Anders kann es z.B. bei so etwas aussehen:

    std::cout << datapoint << endl; // Ausgabe des Messwerts
    

    Wenn man jetzt nach nem Jahr wieder in den Code schaut, dann wäre ohne Kommentar
    nicht klar, was da ausgegeben wird, man müsste schließlich erst einmal wissen, was die Variable datapoint darstellt.

    Ja, man müsste wissen was dir Variable datapoint darstellt. Wenn man es nicht weiss hat man aber ein anderes Problem als zu wissen was diese Zeile macht, man wird den ganzen Code der mit datapoint arbeitet nicht verstehen. Also entweder (schlechte Lösung) bei der Definition von datapoint dazuschreiben was drin steht (und nur dort), oder (bessere Lösung) nen ausreichend sprechenden Namen verwenden. Wobei ich datapoint jetzt nicht schlecht finde. Ich meine "datapoint" mit "Messwert" kommentieren... dafuq? Kann da etwa jemand kein Englisch?

    Weiters halte ich

    Jede Funktion sollte kommentiert werden.
    Wichtig ist, was sie tut, was die Parameter bedeuten, welche Vorbedingungen die Funktion erfordert und was die Funktion zurückliefert.
    Ebenso gehört dazu, welche Expcetion sie wirft und warum, sowie welche Seiteneffekte auftreten können.

    für total übertrieben. Funktionen deren "funktion" sozusagen "offensichtlich" ist, genau so wie die Bedeutung der einzelnen Parameter müssen nicht unbedingt dokumentiert werden.
    Zu viel zu dokumentieren erzeugt auch oft das Problem dass die Dokumentation anfängt zu lügen wenn Änderungen gemacht werden - weil dann oft vergessen wird die Doku anzupassen. Oder auch ein Klassiker; Änderungen in Funktion X verursachen Änderungen in Funktion Y, weil X von Y aufgerufen wird. z.B. welche Exceptions aus X rausfliegen können.

    (Bzw. manchmal lügt die Doku sogar schon am dem 1. Moment. Ich sehe das relativ oft dass Leute ne Doku wo dazuschreiben, bei etwas was sie gerade erst programmiert haben, und die Doku dann einfach was anderes sagt als was die Implementierung macht. Die Unterschiede sind meist im Detail, aber herrjeh, wenn man sich nicht drauf verlassen kann dass es exakt stimmt, dann tut's vermutlich auch die grobe Vorstellung die man durch Funktionsname + Parameternamen bekommt. Zumindest weiss man dann was man nicht weiss und ggf. in der Implementierung nachgucken müsste.)

    Weiters ist jede Zeile Doku die man anpassen oder sogar neu schreiben muss ein weiterer Refactoring-Hemmer. Und Refactoring will man nicht noch mehr ausbremsen als es das automatisch durch das Thema "kein kundensichtbarer Vorteil" schon wird.

    Also lieber gucken dass man seine Bezeichner so wählt dass man mit wenig bis keiner Doku auskommt.

    Was dagegen wichtig ist, ist ne Doku die das grosse Ganze erklärt. Also die grossen Komponenten, wofür sie gut sind und wie sie zusammenspielen. Ein \brief zu jeder Klasse + von Doxygen daraus generierte Übersicht ist oft viel viel mehr Wert als wenn jede Funktion jeder einzelnen Klasse dokumentiert ist, aber keine Kurzbeschreibung was die Klasse überhaupt soll.

    Und nochmal ne Nummer grösser: die wichtigsten Module (Libraries), wo inetwa welche Funktionalität drin ist etc.

    ----

    Macht aber natürlich auch einen Unterschied was man entwickelt. Wenn man langlebige Libraries entwickelt, dann ist es vermutlich wichtiger jede Klasse und jede nicht-triviale Funktion zu dokumentieren. Wenn man ne Anwendung entwickelt, dann ist es eher nicht so wichtig. Und wenn man "lebendigen" Code hat, der sich dauernd ändert und ständig selbst neu erfindet, dann auf jeden Fall bitte nicht jeden Fliegenschiss dokumentieren.


Log in to reply