Ist C++ durch C11 und C14 wieder populärer geworden?
-
Mechanics schrieb:
Man kann die Darstellung von Objekten konfigurieren (mit natvis sogar viel bequemer als früher), man kann eigene Visualizer programmieren, man kann Werte live ändern...
Im Vergleich zu diversen IDE-Frontends für den GDB fällt mir beim VS Debugger
auch immer wieder auf wie angenehm übersichtlich die Objekte dargestellt werden.
Bei einerstd::map
habe ich dort z.b. die Element-Paare direkt als erstes sauber in
einer Liste und kann mir bei Bedarf im "Raw View" die darunter liegende Datenstruktur
genauer ansehen. Möglich, dass ich sie falsch benutzt habe, aber bei anderen Debuggern
muss ich mich da meistens durch die interne Datenstruktur der Implementierung hangeln,
um an die Werte zu kommen.Auch noch positiv: Sind Debug-Informationen und der irgendwoher separat heruntergeladene
Quellcode vorhanden, ist es sehr unproblematisch sich mal eben schnell mit dem Debugger in
ein laufendes Programm einzuhängen und dieses direkt im Quellcode zu debuggen, ohne dass
man dafür ein vollständiges und kompilierbares Projekt benötigt.
Das hatte ich letztens mal mit einem heruntergelanden Programm, bei dem ich nur mal eben
wissen wollte, wie ich einen Bug umschiffen kann, ohne diesen beheben zu müssen,
geschweige denn erstmal das Programm mit all seinen Abhängigkeiten zum kompilieren zu bringen.Wahrscheinlich geht das alles auch mit alternativen IDEs und Compilern, aber erfahrungsgemäss ist das
dort wesentlich pfriemleliger zu konfigurieren, bis es alles mal läuft. Mit VS bin ich meistens deutlich produktiver.Finnegan
-
Ich kann den VC++-Debugger nur mit dem der Java-Debugger vergleichen. Und da ist der teilweise sogar fast besser!
Z.B. das Enum-Werte auch ihre Bezeichner darstellen.
Oder das ich schon seit VC++6.0 (1998?) Edit & Continue benutzen kann (also im laufenden Programm Code ändern und die Stelle neu ausführen, während das Programm seinen Zustand behält), hatte mich damals umgehauen. Und als die Java-Kollegen (als ich von C++ zu Java gewechselt bin) mit stolz von ihrem Edit & Continue in der Java IDE erzählten, habe ich nur müde gelächelt.
Und der Debugger hat sich mächtig weiter entwickelt.
-
Nutzt Ihr Debugger eigentlich viel? Ich mache das naemlich nicht. Irgendwie treffe ich nur ganz selten auf Fehler, bei denen ich mir denke, dass ich die am Besten mit einem Debugger angehen kann.
-
Ja, der ist extrem wichtig. Hier gibts ne riesige alte Codebasis und fast keine Doku. Da hilft der Debugger schon rauszufinden was jetzt eigentlich so abgeht.
-
Gregor schrieb:
Nutzt Ihr Debugger eigentlich viel? Ich mache das naemlich nicht. Irgendwie treffe ich nur ganz selten auf Fehler, bei denen ich mir denke, dass ich die am Besten mit einem Debugger angehen kann.
Ich lasse Tests immer im Debugger laufen, weil ich bei einem Absturz oder einem Deadlock sofort weiß, wo es passiert.
Ab und zu ist es nützlich einen Breakpoint für das Auftreten einer Exception zu setzen. Das bringt natürlich nur etwas, wenn man Exceptions nur für Ausnahmen verwendet.
Manchmal deckt sich das erwartete Verhalten einer Funktion nicht mit dem beobachteten Ergebnis. Da hilft ein Debugger schon immens beim Verstehen.
-
Gregor schrieb:
Nutzt Ihr Debugger eigentlich viel?
Hab langsam verlernt, wie man den benutzt.
-
TyRoXx schrieb:
Ich lasse Tests immer im Debugger laufen, weil ich bei einem Absturz oder einem Deadlock sofort weiß, wo es passiert.
Dafuer braucht man ja erstmal keinen Debugger, sondern nur Debug Informationen. In Fortran kompiliere ich Code zum Testen zum Beispiel mit
ifort -warn nousage -traceback -ftrapuv -CB -O0 -g -check uninit -check pointers
Das ist super. Ich kriege damit bei jeder Kleinigkeit einen Fehler mit sehr genauer Angabe, wo der auftritt.
-
Gregor schrieb:
Dafuer braucht man ja erstmal keinen Debugger, sondern nur Debug Informationen. In Fortran kompiliere ich Code zum Testen zum Beispiel mit
ifort -warn nousage -traceback -ftrapuv -CB -O0 -g -check uninit -check pointers
Das ist super. Ich kriege damit bei jeder Kleinigkeit einen Fehler mit sehr genauer Angabe, wo der auftritt.
Das fällt war streng genommen unter "keinen Debugger benutzen", als verwöhnter IDE-User drücke ich da aber lieber zum starten einfach "die andere" Taste und starte das Programm im Debugger um an diese Informationen zu kommen.
Zumal ich dann auch noch gleich den Quellcode-Kontext sehe in dem der Fehler aufgetreten ist und mir ansehen kann was denn grad im Speicher so los ist.Finnegan
-
Gregor schrieb:
Nutzt Ihr Debugger eigentlich viel?
Ja, sehr viel. Wir haben sehr viel sehr "komplexen" Code. Komplex nicht im Sinne von hochkomplexe mathematische Algorithmen (haben wir auch, aber nicht meine Baustelle), sondern komplex im Sinne von verteilt über zig Komponenten und Prozesse und sehr viel Code von 100 Leuten über Jahrzehnte hinweg geschrieben und keiner kennt sich komplett aus usw...
-
Mechanics schrieb:
Gregor schrieb:
Nutzt Ihr Debugger eigentlich viel?
Ja, sehr viel. Wir haben sehr viel sehr "komplexen" Code. Komplex nicht im Sinne von hochkomplexe mathematische Algorithmen (haben wir auch, aber nicht meine Baustelle), sondern komplex im Sinne von verteilt über zig Komponenten und Prozesse und sehr viel Code von 100 Leuten über Jahrzehnte hinweg geschrieben und keiner kennt sich komplett aus usw...
Mein Eindruck ist eigentlich, dass Debugger bei zunehmender Komplexitaet des Codes immer weniger bringen. Komplexitaet heisst fuer mich in diesem Fall, dass ein lokales Verstaendnis einer Codestelle nicht ausreicht, um den Code debuggen zu koennen. Debugger sind aber gerade darauf ausgelegt, lokal eingreifen zu koennen und sich den lokalen Zustand des Programms an einer Stelle anzugucken.
-
Gregor schrieb:
Mechanics schrieb:
Gregor schrieb:
Nutzt Ihr Debugger eigentlich viel?
Ja, sehr viel. Wir haben sehr viel sehr "komplexen" Code. Komplex nicht im Sinne von hochkomplexe mathematische Algorithmen (haben wir auch, aber nicht meine Baustelle), sondern komplex im Sinne von verteilt über zig Komponenten und Prozesse und sehr viel Code von 100 Leuten über Jahrzehnte hinweg geschrieben und keiner kennt sich komplett aus usw...
Mein Eindruck ist eigentlich, dass Debugger bei zunehmender Komplexitaet des Codes immer weniger bringen. Komplexitaet heisst fuer mich in diesem Fall, dass ein lokales Verstaendnis einer Codestelle nicht ausreicht, um den Code debuggen zu koennen. Debugger sind aber gerade darauf ausgelegt, lokal eingreifen zu koennen und sich den lokalen Zustand des Programms an einer Stelle anzugucken.
Ich sehe das genau umgekehrt: Debugger sind dann genial wenn es nicht um eine limitierte Codestelle geht sondern um komplexe Abhängigkeiten zu anderen Codestellen. Denn lokal limitierte Fehler sind relativ simpel auch ohne Debugger zu finden. Gerade aber wenn die Abhängigkeiten zu anderen Codestellen komplex werden, dann sind Debugger enorm hilfreich.
-
Wenn man viel OOP macht, ist es dann überhaupt noch gut möglich den eigentlichen Signalfluß zu überblicken? Ich stelle mir das gruselig vor, erst recht wenn das Code von einem Fremden ist.
-
Schrauber schrieb:
Wenn man viel OOP macht, ist es dann überhaupt noch gut möglich den eigentlichen Signalfluß zu überblicken? Ich stelle mir das gruselig vor, erst recht wenn das Code von einem Fremden ist.
Was hat das mit OOP zu tun?
Mein Vater druckt sich für seine 100-200 Zeilen langen Funktionen gerne Struktogramme aus. Sowas macht natürlich keinen Sinn, aber deswegen ist es noch lange nicht gruselig.
-
Na, ich stelle mir das ziemlich wüst vor, wenn an einem Prozess ziemliche viele Klassen beteiligt sind. Da durchzusteigen, besonders wenn man es nicht selbst geschrieben hat, ist bestimmt schwer.
-
Dafür gibt es die beiliegenden Dokumentation.
-
C++ geht das doch ganz gut, den Flow nachzuvollziehen.
Entwickelt mal eine schöne Spring-Applikation in Java (mit JPA und allem drum und dran) und sagt, dass ihr das könnt.
-
Schrauber schrieb:
Na, ich stelle mir das ziemlich wüst vor, wenn an einem Prozess ziemliche viele Klassen beteiligt sind. Da durchzusteigen, besonders wenn man es nicht selbst geschrieben hat, ist bestimmt schwer.
Im Gegenteil!
Die Klassen haben sprechende Namen und tun supi nur das tun, was ihr ureigendster Zweck ist und nix anderes. Keine Monsterklassen. Statt irgendwelcher halbsinnfreien Funktionen zum Ein-/Ausloggen mit unbekannten historisch gewachsenen hooks, callbacks, tweaks, hacks und Kundenanpassungen gibt es nur noch einen "LoginManager" und und der heißt einfach Pfoertner. Will die große grüne Tür im Lager immer wissen, wer eingeloggt ist, (nachträglicher verrückter Kundenwunsch) wirft sie einen einfachen LoginObserver aus und läßt ihn vom Pförtner registrieren. Alles ganz kleine Klassen und alle Methoden so zwischen 1 und 6 Zeilen. Aller Code offensichtlich für sich richtig. Schawupps, die Agilität (Fähigkeit, vom Chef auf der Messe aufgeschnappte Ideen in nullkommanix einzubauen) ist enorm und man läßt fast keine Fehler mehr zum Kunden durch. Sogar faktisch gar keine, nur darf man das nicht behaupten, aber ich behaupte es und mache es.Schrauber schrieb:
Na, ich stelle mir das ziemlich wüst vor, wenn an einem Prozess ziemliche viele Klassen beteiligt sind. Da durchzusteigen, besonders wenn man es nicht selbst geschrieben hat, ist bestimmt schwer.
Es ist nicht notwendig, da durchzusteigen. Es ist überhaupt nichtmal sinnvoll, es zu versuchen. Die Abhängigkeiten sind wutzegal. Ich frage ja auch nicht nach, wo mein Bäcker sein Mehl und Wasser und Salz herkriegt und wo der Müller seine Ersatzmühlsteile kauft und wo die Sonne ihre Energie her hat und so. Kaufe brötchen für 13 bis 40 ct, je nach Laune und lege Käse drauf und futtere sie. *glücklich*.
OOP ist unglaublich geil, wenn man sie vergewaltigt und als Zweckmittel benutzt, um brutal einfachen Code zu bauen, den jeder Azubi beim ersten Lesen sofort versteht. Und darüberhinaus hat solcher Code sogar die starke Tendenz, am Ende schneller zu sein als handoptimierter Großfunktionscode. Wenn ich fremden Code beschleunigen sollte, würde ich ihn immer zuerst vereinfachen, und dabei wird er ganz sicher langsamer. Dann weiter vereinfachen. Und noch weiter. Und dann wird er schneller. Und dann Unfug rausmachen, wie sort() oder Indexzugriffe auf Listen und er wird um Größenordnungen schneller. Und dann tolle Algos aus Wikipedia oder per Nachfrage von hier einbauen und noch zwei Größenordnungen rausholen, was aber wirklich nur geht, weil es kein Großfunktionscode mehr ist.
So isses.
-
Techel schrieb:
Dafür gibt es die beiliegenden Dokumentation.
Alle paar Wochen kann ich einen anderen Kollegen mit dem immer selben Witz hochnehmen:
Neverending runnig gag:Er hat fleißig debuggt und kömmt in mein Büro und stellt freundlich aber bestimmt fest, daß es an unseren Funktionen wohl doch liegen wird, daß der Kunde weint. Ich unterbreche meine Arbeit immer sofort und in wenigen Minuten sind wir ganz in der Materie seines Problems. Ganz gewiss nach kurzer Zeit wird er auch mal Zweifel haben, ob er selber dran schuld war, weil er unsere Funktion mit Mist gefütter hat, oder ob unsere Funktion aus Heu Mist erzeugt. Dann verweise ich ihn freundlich auf unsere Dokumentation. Er fragt: "Ach, da gibt es eine Doku? Wo?", und das ganze Büro lacht, das Opfer des Scherzes herzlich mit, daß man ihn wieder drangekriegt hat. Allerbekannt haben wir keine Doku.
-
Shade Of Mine schrieb:
Ich sehe das genau umgekehrt: Debugger sind dann genial wenn es nicht um eine limitierte Codestelle geht sondern um komplexe Abhängigkeiten zu anderen Codestellen. Denn lokal limitierte Fehler sind relativ simpel auch ohne Debugger zu finden. Gerade aber wenn die Abhängigkeiten zu anderen Codestellen komplex werden, dann sind Debugger enorm hilfreich.
Seh ich genauso. Auch gut, wenn man den Prozess nachvollziehbar wiederholen kann. So in der Art, es passiert "etwas", und man hat keine Ahnung, wo das überhaupt herkommt und wer das wozu braucht. Dann findet man raus, was dieses etwas ist und setzt da einen Breakpoint und dann sieht man schon mal im Callstack, wo das ganze herkommt und kann dann nachvollziehen, warum das passiert und wer dafür verantwortlich ist. Oder was wir öfter haben, irgendwelche Prozesse hängen sich ab und zu auf, weil sie in Timing Situationen reinkommen, wo sie gegenseitig aufeinander warten. Dann kann man an der Stelle auch alle Callstacks (sind oft mehrere Threads in jedem Prozess beteiligt) anschauen und dann ist auch oft klar, woran das liegt. Oder einfach irgendwas "durchdebuggen", wo virtuelle Funktionen aufgerufen werden und man erstmal nicht weiß, wo irgendwelche Implementierungen überhaupt herkommen.
-
Also es gibt Dinge die sind einfacher zu debuggen und Dinge die sind schwieriger zu debuggen.
Die Komplexität des Programms spielt dabei nur begrenzt eine Rolle. Man kann einfache Programme sehr schwer zu debuggen machen aber auch oft komplexe Programme einfach zu debuggen.Ein wichtiger Punkt für mich ist dabei wie aussagekräftig der Callstack ist. Wenn der Callstack mich von main() ausgehend, über alle Funktionen die für den aktuellen Zustand des Programms mitverantwortlich sind, bis zu der Stelle hin führt, wo das Problem aufgetreten ist, dann ist das meist super einfach zu debuggen. (Bzw. es sollte halt wenigstens alles im Callstack sein was für den Zustand der Problematischen Variablen/Objekte verantwortlich ist.)
Wenn der Callstack nur aus
main->DispatchMessage->(50 Level Framework-/OS-Funktionen)->OnDingsiEvent
besteht, dann wird es schwieriger. Callstacks alamain->Dingsi::Run->Dingsi::CallHandler->(10 Framework/OS Funktionen)->[AnonymousCompletionHandlerClass42]::operator()
sind auch nicht schön.Und ein zweiter wichtiger Punkt ist für mich wie einfach bzw. schwer es überhaupt möglich ist sinnvolle Breakpoints zu setzen. Das kann z.B. dadurch deutlich erschwert werden dass übertrieben "generisch" (nicht im Sinn von Templates jetzt) programmiert wurde und zu viel in Config-Files verlagert.
Ist schwer zu beschreiben ohne Romane zu verfassen (die dann verständlicherweise keiner liest), aber ich versuchs mal...
Ich denke da an eines unserer Programme (mit dem ich gottseidank kaum zu tun habe). Das Ding instanziert per XML File gesteuert haufenweise "Dinge" Objekte. Meist Integer-Dinge, String-Dinge, manchmal Container-Dinge. Und dann gibt es auch noch die lustigen "Objekt-Dinge". Wobei ein "Objekt-Ding" eine Map ist die "benannte Dinge" enthält. Also nen Namen auf ein (abstraktes!) Ding abbildet. So wird dann ein lustiger Dinge-Graph aufgebaut -- ausgehend von einem zentralen, globalen Wurzel-Ding. Mit dem Debugger so ein "Ding" zu inspizieren ist also schonmal super-mega-umständlich. Denn erstmal muss man das Ding von der Wurzel ausgehend überhaupt mal finden.
Weites sind die Dinge natürlich auch beobachtbar, haben also Change-Listener. An die kann man verschiedene Observer-Klassen dranhängen, natürlich auch alles per XML konfiguriert. Das ganze geht sogar so weit dass man z.B. per XML File Bedingungen definieren kann die noch geprüft werden sollen bevor der konfigurierte Handler aufgerufen werden soll. Die Bedingungen sind natürlich ebenso Objektgraphen, also z.B. Or-Objekte die dann Kinderlein haben die sie verodern, Equals-Checker Objekte die wieder irgendwelche "Dinge" auf Gleichheit prüfen usw.
Und natürlich gibt es auch konfigurierbare "wiederverwendbare" Handler-Klassen. Die Dinge kopieren, auf einen bestimmten Wert setzen, Container-Dinge ausleeren - lauter so lustige Sachen.Jetzt ist der Fehler dass wenn man dieses oder jenes macht bzw. dem Programm füttert, danach das Ding "Foo.Bar.Baz[42].SchrunsTschagguns.NumberOfBatsInTheRoof" den falschen Wert hat - es fehlt eine Fledermaus.
Und nu' setz nen sinnvollen Breakpoint.
Klar, man kann sich irgendwie behelfen. Man kann ne eigene Dummy-Handler Klasse schreiben, und die im XML File beim Ding "Foo.Bar.Baz[42].SchrunsTschagguns.NumberOfBatsInTheRoof" als "Changed" Handler eintragen. Dann kann man in der Handler-Funktion der Dummy-Handler Klasse nen Breakpoint setzen. [Sarkasmus]Geht ja schnell.[/Sarkasmus]
Und dann hat man nen tausende Zeilen langen Callstack voll mit lauter generischen, nichtssagenden Klassennamen.