Bibliothek für Kontrollausgabe
-
Hi,
ich habe ein größeres Programm (15000 Zeilen) geschrieben und möchte nun ein komfortable Kontrollausgabe einbauen. Bisher sieht das bei mir typischerweise wie folgt aus:
Tree::Tree(const Tree& tr) : Base_Tree<Node, Node_Container>(tr.num_sites(), tr.num_mutation_rates()) { const bool OUTPUT_DEBUG = 1; // Kontrollausgabe machen? ofstream* out_strm = in_out_streams::ostrm(OUTPUT_FILE); // Outstream für Kontrollausgabe holen if (OUTPUT_DEBUG) in_out_streams::header_begin(out_strm, "Tree(const Tree& tr)"); // Als erstes Text ausgeben, der besagt, dass hier die Funktion beginnt ... // (Code) if (OUTPUT_DEBUG) // irgendeine Kontrollausgabe { *out_strm << "total_intensity: " << total_intensity << endl; *out_strm << "recomb_intensity: " << recomb_intensity << endl << endl; } ... // (Code) if (OUTPUT_DEBUG) in_out_streams::header_end(out_strm, "Tree(const Tree& tr)"); // Als letztes Text ausgeben, der besagt, dass hier die Funktion endet }Aus folgenden Gründen gefällt mir das nicht:
- Das An- und Ausschalten der Ausgabe ist unkomfortabel. Die obige Funktion z.B. ist Teil der Datei "sim_tree.cpp" im Ordner "tree". Ich würde gerne alle Ausgaben in der Datei "sim_tree.cpp" bzw. im Ordner "tree" bzw. im ganzen Programm an- und ausschalten können.
- Die Ausgabe vom Header (in_out_streams::header_begin(...)) und seinem Gegenstück (wie nennt man das eigentlich: base, bottom, foot?) sollte stärker automatisiert sein, d.h.
* ich sollte nicht gezwungen sein, den Funktionsnamen einzugeben
* man sollte noch anderen Angaben bekommen (Dateiname, Zeilennummer)Weiss jemand, ob es dazu schon was gibt (in Boost war ich nicht fündig) oder, falls nicht, wie man es per Hand am besten macht?
-
Kontrollausgaben programmiert man selbst:
...
ofstream test;
int iAnyInteger=2;
float fAnyFloat=2.5;
char cAnyString[]="hallo";
...
test.open("test.tst");
...
test << "--> " << iAnyInteger << " " << fAnyFloat << " " << cAnyString << endl;
...
...
test.close();Ich verwende diese Methode seit den Zeiten, als es noch keine Debugger gab
-
wieso nich so in etwa?
#ifndef _DEBUG #define DEBUG_OUTPUT (X) std::cout << X << std::endl #else #define DEBUG_OUTPUT (X) 0 #endiffor (size_t i (0); i != max; ++i) { //... DEBUG_OUTPUT (i << " / " << max); }sollte ganz gut funzen denk ich...
bb
-
unskilled schrieb:
#ifndef _DEBUG #define DEBUG_OUTPUT (X) std::cout << X << std::endl #else #define DEBUG_OUTPUT (X) 0 #endifBei der ersten Präprozessordirektive sollte es wohl
#ifdefheissen. Und statt0würde ich eher;oder{}schreiben
-
Nexus schrieb:
Und statt
0würde ich eher;oder{}schreiben
((void)0)
oder eine inline funktion
inline void noop(){}verwenden die nichts macht...
-
Nexus schrieb:
Bei der ersten Präprozessordirektive sollte es wohl
#ifdefheissen.Joar - sry ^^
Shade Of Mine schrieb:
((void)0)
Joar - so wärs richtiger... Aber in dem Fall ists find ich ziemlich egal...
bb
-
Bei der vorgeschlagenen Lösung, scheint es mir ein Problem, dass man mittels _DEBUG alle Kontrollausgabe an- oder ausschalten kann. Wenn ich in meinem Programm aber alle Kontrollausgaben (15000 Zeilen Code und wachsend) anschalte, wird das ziemlich unübersichtlich. Am liebsten wäre mir eine baumartige Struktur:
- tree: an/aus - sim_tree: an/aus - Tree::Tree(const Tree& tr): an/aus - Tree::Tree(): an/aus - Tree::prob(): an/aus ... - tree_rearranger: an/aus ... - subst_prob: an/aus ... ... - node: an/aus ...Hier seien "tree" und "node" Ordner, "sim_tree", "tree_rearranger" und "subst_prob" Source-Dateien und "Tree::Tree(const Tree& tr)", "Tree::Tree()" und "Tree::prob()" Methoden. Mittels "an" und "aus" kann entschieden werden, ob alle Kontrollausgaben in Ordner/Datei/Methode angeschaltet werden (so ähnlich wie das manchmal beim Auswählen von Dateien auch ist).
Ich hoffe, ich bin nicht der Erste, der sowas haben will (wäre dann wohl auch ein Zeichen dafür, dass das nicht sinnvoll ist).
-
Shade Of Mine schrieb:
Nexus schrieb:
Und statt
0würde ich eher;oder{}schreiben
((void)0)
oder eine inline funktion [...] verwenden die nichts macht...Das versteh ich jetzt nicht... Wieso eine Null oder eine Inline-Funktion, aber keine Leeranweisung bzw. ein leerer Block?
@ ingobulla:
Du könntest eigene Makros definieren und dann in den erwünschten Codeteilen spezifisch abfragen, ob nun eine Debug-Ausgabe stattfinden soll oder nicht. Für hierarchische Abfragen schachtelst du eben mehrere#ifdefs.
-
Nexus schrieb:
Das versteh ich jetzt nicht... Wieso eine Null oder eine Inline-Funktion, aber keine Leeranweisung bzw. ein leerer Block?
Was wenn jemand ein if verwendet:
if(foo) DEBUG_OUT("blabla");
was passiert, wenn du jetzt aus DEBUG_OUT ein {} machst?
nichts wildes, aber stell dir mal folgendes vor:if(foo) DEBUG_OUT("bla bla");
else DEBUG_OUT("blu blu");plötzlich haben wir einen syntax fehler, weil
if(foo) {} ; else {} ;
nicht korrekt ist...weiters sollten solche makros auch immer nur void liefern, damit nie nie nie jemand auf so eine idee kommt:
int i = DEBUG_OUT("blup");
deshalb immer nach void casten...
-
Fuer sowas nimmt man Logging-Bibliotheken, die die Logger hierarchisch ordnen koennen:
http://logging.apache.org/log4cxx/index.html
http://log4cpp.sourceforge.net/
http://log4cplus.sourceforge.net/
http://pantheios.sourceforge.net/ (keine Hierarchie)(mit "logging C++" waren die uebrigens alle auf der 1. Trefferseite bei Google... )
An Filenamen & Zeilennummer rankommen ist auch relativ einfach, dafuer gibts vom Compiler definierte Macros, vllt. auch fuer den Funktionsnamen (die Macros muesstet aber selbst im Handbuch nachschlagen, hab k.A. mehr).

-
Blue-Tiger schrieb:
An Filenamen & Zeilennummer rankommen ist auch relativ einfach, dafuer gibts vom Compiler definierte Macros, vllt. auch fuer den Funktionsnamen (die Macros muesstet aber selbst im Handbuch nachschlagen, hab k.A. mehr).

__LINE__
__FILE__
BOOST_CURRENT_FUNCTION
-
@ Shade Of Mine:
Vielen Dank für die Erläuterung, diese Problematik war mir bis jetzt nicht bewusst.
-
Wer braucht so komplizierte Dinge. Man muss sein Programm-Design nur übersichtlich halten. Dann helfen jeder Debugger oder eigene Kontrollausgaben.
-
berniebutt schrieb:
Wer braucht so komplizierte Dinge. Man muss sein Programm-Design nur übersichtlich halten. Dann helfen jeder Debugger oder eigene Kontrollausgaben.
Was ja auch wunderschön fuinktioniert wenn man der einzige ist der daran arbeitet und die Größe unter der Tausend Klassen-Grenze bleibt.

-
@ Fellhuhn
Gerade wenn mehrere Leute an einem Projekt arbeiten, kommt es auf ein sauberes Design und eben auf einen Kontroll-Mechanismus an. Irgendwo ist Mist und niemand merkt es. Die Fehlersuche war schon immer der grösste Aufwand der Programmierung.
-
Wenn alles Knorke wäre im Code würde man aber auch nicht so schön saftige Supportverträge abschließen und sich daran dumm und dämlich verdienen.

Ne, leider wird es selten was mit komplett durchgezogenen Designmustern etc. weil einigen einfach die Erfahrung fehlt, niemand die Zeit (und so das Geld) hat diese einzulernen. Ebenso müssen Änderungen schnell erfolgen und jahrzehnte alter Code integriert werden und das ganze noch mit alten Compilern laufen. Nicht immer funzt das.

-
@ Fragesteller
Du siehst, das Ziel ist nicht einfach.
@ Fellhuhn
Programmieren war noch nie einfach. Wer keine Ahnung oder nur ungenügende Erfahrung damit hat, sollte es sein lassen - oder einen anderen Job suchen.