Stream-Objekt im Debugmodus komplett wegoptimieren?
-
Ich verwende ein Logging-System, das an log4cpp bzw. log4j angelehnt ist. Vorherrschend ist folgender Syntax, der einen sehr bequemen Umgang mit gemischten Strings und Zahlenwerten erlaubt:
LOGWARN << "Der Zähler ist zu hoch: " << counter;
LOGWARN (und die Geschwister LOGDEB, LOGINFO usw.) sind Macros, die sich wie folgt auflösen:
logger.warn() << "Der Zähler ist zu hoch: " << counter;
warn()
erzeugt als Rückgabewert ein Objekt mit einemoperator<<()
, der sich somit wie ein stream anfühlt und die rvalues nach und nach in seinstringstream
-member stopft. Der Clou ist der Destructor des Objekts, der den Inhalt desstringstream
nun an denlogger
übergibt, daher ist keinendl
notwendig.Die verschiedenen Log-Levels (DEBUG, INFO, WARN, ERROR usw.) erlauben es, zur Laufzeit mal mehr, mal weniger wichtige Nachrichten auszufiltern.
Nun die Frage: Im Release-Modus (Compilerschalter) würde ich gerne alle LOGDEB-Macros so umfunktionieren, dass möglichst die gesamte Zeile komplett wegoptimiert wird. Hätte ich einen Syntax wie
debug("blabla")
wäre die Sache einfach, das LOGDEB-Macro kann ich jedoch nicht einfach leer definieren, weil der Stream-Inhalt dann übrigbliebe.#define LOGDEB //
wäre zu schön...
Als Einziges fällt mir ein, LOGDEB wie folgt zu definieren:
#define LOGDEB dummyDebug()
und dass diese Funktion ein ebensolches Stream-like Objekt zurückgibt, dessen
operator<<()
einfach nichts anderes macht als*this
zurückzugeben.Hat jemand Erfahrung, in wie weit ein Compiler so ein faules Stück erkennt und ggf. weiter wegoptimiert? Oder eine gute Idee?
Performance ist kein Problem, mir geht es nur um das Prinzip, ob es noch besser geht.
Bedingung: Der Code soll nicht umgeschrieben werden (also z.B. alleLOGDEB << "xxx"
ändern indebug("xxx")
).Edit: Die Debug-Ausgaben sollen natürlich im Release-Modus verschwinden, nicht im Debug-Modus...
-
minastaros schrieb:
Nun die Frage: Im Debug-Modus (Compilerschalter) würde ich gerne alle LOGDEB-Macros so umfunktionieren, dass möglichst die gesamte Zeile komplett wegoptimiert wird. Hätte ich einen Syntax wie
debug("blabla")
wäre die Sache einfach, das LOGDEB-Macro kann ich jedoch nicht einfach leer definieren, weil der Stream-Inhalt dann übrigbliebe.Dann bastel dir doch eine solche Syntax:
#ifdef DEBUG_MODE #define DEBUG_OUT(x) logger.warn() << x #else #define DEBUG_OUT(x) #endif
edit: Oh, habe die Bedingung mit dem Umschreiben übersehen.
-
#define CONCAT(a,b) a ## b #ifdef _DEBUG #define LOGWARN CONCAT(/,/) #else #define LOGWARN logger.warn() #endif int main() { LOGWARN << "Sakra!"; :::
Mein VS11 macht das.
Edit: Und der gcc anscheinend nicht.
-
#ifdef _DEBUG #define LOGWARN if(true){}else logger.warn() #else #define LOGWARN logger.warn() #endif
bzw. statt logger.warn kann man auch ein noop oder was auch immer verwenden - es muss nur den op<< anbieten, ausgeführt wird der code ja nicht, also reicht rein syntaktische korrektheit.
-
Shade Of Mine schrieb:
#ifdef _DEBUG #define LOGWARN if(true){}else logger.warn() #else #define LOGWARN logger.warn() #endif
bzw. statt logger.warn kann man auch ein noop oder was auch immer verwenden - es muss nur den op<< anbieten, ausgeführt wird der code ja nicht, also reicht rein syntaktische korrektheit.
Danke, genau an sowas dachte ich!
-
Guck dir Boost.Log an.
Das kann das was du willst und noch einiges mehr.
z.B. wertet Boost.Log nichtmal die Expressions für Nachrichten aus deren Logger dynamisch (d.h. zur Laufzeit) deaktiviert wurde.Ganz grob hab ich den Mechanismus den Boost.Log verwendet gerade eben hier beschrieben: http://www.c-plusplus.net/forum/p2362141#2362141