TRACE Makro ohne footprint im Release



  • Hallo zusammen,

    ich baue grad ein TRACE Makro, das im Release Modus keinen Footprint im Code hinterlassen soll. Hier mein erster Ansatz:

    #include <windows.h>
    
    #include <iostream>
    #include <sstream>
    #include <iomanip>
    
    struct Tracer
    {
       std::ostringstream oss_;
    
       Tracer( const char* FileName, const char* FuncName, unsigned int LineNumber )
       {
          oss_ << FileName << ": " << FuncName << "(" << LineNumber << "): ";
       }
    
       void trace()
       {
          ::OutputDebugString( oss_.str().c_str() );
       }
    
       template<typename T, typename... U>
       void trace( const T& head, const U& ...tail )
       {
          oss_ << head;
          trace( tail... );
       }
    };
    
    template<typename T, typename... U>
    void trace( const T& head, const U& ...tail )
    {
    }
    
    #ifdef DEBUG
       #define TRACE trace;
    #else
       #define TRACE Tracer( __FILE__, __func__, __LINE__ ).trace
    #endif
    

    Soweit, so gut. Das einzige Problem, dass der Code noch hat ist die Auswertung der Parameter im Releasemodus. Im Fall von

    TRACE( someFunc(), obj.GetName() );
    

    werden someFunc und obj.GetName() noch aufgerufen, um die Parameter für die Tracefunktion zu bestimmen. Kriegt man das auch noch irgendwie eliminiert?

    Edit:
    Code korrigiert



  • ich glaub der gängige trick ist es das ganze ein ein

    do{ /* your code */ } while(0);
    

    zu packen, das wir dann komplett raus optimiert.



  • whiler schrieb:

    ich glaub der gängige trick ist es das ganze ein ein

    do{ /* your code */ } while(0);
    

    zu packen, das wir dann komplett raus optimiert.

    Der Trick mit dem do while ist nicht um Code weg optimieren zu lassen. Tatsächlich wird ja die Schleife genau einmal durchlaufen, also kann man das gar nicht so einfach wegoptimieren. Die do while Konstruktion nimmt man häufig um Makros wie Funktionsaufrufe aussehen zu lassen. Dann muss man aber das letzte Semikolon hinter dem while(0) weglassen.



  • Stichwort Variadic Macros

    #ifdef DEBUG
      #define TRACE(...) Tracer( __FILE__, __func__, __LINE__ ).trace(__VA_ARGS__)
    #else
      #define TRACE(...)
    #endif
    


  • Zum eigentlichen Problem. Möglicherweise irre ich mich aber es gibt einige Ausdrücke die nicht ausgewertet werden in C++ (unevaluated context). Ein bekannter davon ist sizeof . Wenn du also etwas wie sizeof( trace(someFunc(), obj.GetName()) ) compilierst dann werden die Funktionen zur Laufzeit nicht aufgerufen, sondern nur derren Rückgabewerte vom Compilier analysiert.



  • Erst ein Mal Danke für die Antworten.

    @osdt
    Variadic Macros sind nicht typsicher, und wenn jemand den Formatspezifizierer vermurkst können seltsame Sachen passieren.

    @sebi707
    Der sizeof Ansatz sieht schon ganz gut aus, aber wie kriegt man das syntaktisch hin? Mein Ansatz ersetzt ja das TRACE durch ein temp. Objekt samt Funktionsaufruf, und wenn ich das sizeof Konstrukt benutze muss ich das noch mal klammern.

    Edit:
    Das geht ja noch einfacher 🙂

    #define TRACE sizeof
    


  • DocShoe schrieb:

    @osdt
    Variadic Macros sind nicht typsicher, und wenn jemand den Formatspezifizierer vermurkst können seltsame Sachen passieren.

    Ich glaub da verwechselst du was. Variadic Macros sind ja nur Textersetzung und man keine Formatspezifizierer wenn man ohne Macro auch keine brauchte.



  • Hab da wohl wirklich was falsch verstanden. Die Beispiele, dich gefunden habe, haben immer sowas wie printf nachgebaut und da hab ich wohl was nicht richtig verstanden.


Log in to reply