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 einem operator<<() , der sich somit wie ein stream anfühlt und die rvalues nach und nach in sein stringstream -member stopft. Der Clou ist der Destructor des Objekts, der den Inhalt des stringstream nun an den logger übergibt, daher ist kein endl 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. alle LOGDEB << "xxx" ändern in debug("xxx") ).

    Edit: Die Debug-Ausgaben sollen natürlich im Release-Modus verschwinden, nicht im Debug-Modus...


  • Mod

    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


Anmelden zum Antworten