Haben diese Defines irgendeinen Sinn?



  • Du hast behauptet die Makros wären "Write Only Code".

    Deswegen wollte ich ja meine Meinung zu Makro's etwas koorigieren, als ich (etwas vorschnell) meinte nimm keine Makro's.

    Aber wenn ich in das Bosst Logging Makro anschaue, dann ist das halt nicht für's Debugging entwickelt worden. Und dann kommt das eine auf das andere und der Stil überträgt sich auf den Programmierstil, man verbesserte ein Sub-Makro und peng trit ein Fehler auf. Mir fehlt da einfach der Gedanke das auch mal ein Fehler auftauchen kann,... 😞

    Du bist aber nicht einfach zu verstehen, wenn du die Programmiersprachen wechselst und man zum Teil raten kann, auf was du dich beziehst.

    Ich werde noch die Effiziens des Boost Logging Makro testen. Aber gibt mir Zeit.

    ---

    Ich kenne folgende Einsatzarten von Makro's:
    1.) Definition von Konstanten (extern ist unschön), abkürzende Schreibweisen (falls typedef nicht funktioniert)
    2.) Sicherstellung des Einbindens von Code ins Assembly (für Code Verschleierung)
    3.) Makro als Compile-Zeit Funktion



  • Bitte ein Bit schrieb:

    Ich kenne folgende Einsatzarten von Makro's:
    1.) Definition von Konstanten (extern ist unschön), abkürzende Schreibweisen (falls typedef nicht funktioniert)
    2.) Sicherstellung des Einbindens von Code ins Assembly (für Code Verschleierung)
    3.) Makro als Compile-Zeit Funktion

    1. kann ich nicht nachvollziehen. 2) auch nicht. Und 3 auch nicht.

    Debuggen, natürlich assert. Auch

    #define SHOW(x) cout<<(#x)<<'='<<(x)<<'\n';
    

    Aufbau von Sachen, die ein wenig Reflexionartiges machen

    #define LEARNTYPE(x) registerType(#x,new LoadSaveCreateCopyDelete<T>);
    

    Logging, wo bei ausgeschaltetem Log die zu loggenden Ausdrücke NICHT ausgewertet werden müssen.
    Reparieren fremden Codes, mißratener Bibliotheken und Compiler

    //repariert alte MS-Compiler
    #define for if(false);else for
    
    //viel praktischer
    #define cout cout<<
    
    //ich bin hauptschule
    #define sin(x) sin(x*3.14/180)
    
    //da vertippe ich mich immer
    #define retrun return
    
    //und natürlich dieses Meisterwerk perfiden Humors
    #define ever (;;)
    


  • Codegenerierung.



  • Kellerautomat schrieb:

    Codegenerierung.

    Hab ich in den letzten Jahren immer mit Templates gemacht.

    #include <iostream>
    using namespace std;
    
    template<int n>
    struct TuWas{
        static void tuWas(){
            TuWas<n-1>::tuWas();
            cout<<n<<'*'<<n<<'='<<n*n<<'\n';
        }
    };
    template<>
    struct TuWas<0>{
        static void tuWas(){
        }
    };
    
    int main(){
        TuWas<10>::tuWas();
    }
    


  • #include <iostream>
    // Kompiliert mit gcc 4.8 unter Codeblocks
    #include <array>
    #include <boost/log/trivial.hpp>
    #include <ctime>
    #include <chrono>
    #include <iomanip>
    #include <thread>
    #include <windows.h>
    #include <mutex>
    
    using std::chrono::duration_cast;
    using std::chrono::milliseconds;
    using std::chrono::steady_clock;
    using std::chrono::system_clock;
    
    std::mutex g_pages_mutex;
    
    void WriteToLog(const std::string& Msg)
    {
        g_pages_mutex.lock();
        try
        {
            //*******************************
            std::time_t now_c = system_clock::to_time_t(system_clock::now());
            std::tm* Time = gmtime(&now_c);
            DWORD ThreadID = GetCurrentThreadId();       // weis nicht warum std::this_thread::get_id() immer 1 einzeigt
    
            // Ausgabe boost: [2013-10-14 22:33:58.634517] [0x000015c4] [trace]   Hallo Welt
            std::cerr << "{" << (Time->tm_year + 1900) << "-" << (Time->tm_mon + 1) << "-" << Time->tm_mday << " " <<
                Time->tm_hour << "-" << Time->tm_min << "-" << Time->tm_sec << "} " << ThreadID << " (trace)" << Msg <<
                std::endl;  // Sollte eigentlich "\n" stehen, damit nicht ständig geflusht wird
                //"\n";  
        }
        catch (...)
        {
            std::cerr << "Irgentein Fehler ist aufgetreten!\n";
        }
        g_pages_mutex.unlock();
    }
    
    void Test()
    {
        static const size_t Max = 1000;
        // Variablen
        size_t i;
    
        auto T3 = steady_clock::now();
        for (i = 0; i < Max; i++)
        {
            BOOST_LOG_TRIVIAL(trace) << "Hallo Welt\n";
        }
        auto T4 = steady_clock::now();
    
        auto T1 = steady_clock::now();
        for (i = 0; i < Max; i++)
        {
            WriteToLog("Hallo Welt\n");
        }
        auto T2 = steady_clock::now();
    
        std::cout << "\n\nZeit 1 (std::cerr): " << duration_cast<milliseconds>(T2 - T1).count() << "ms \n";
        std::cout << "\n\nZeit 2 (BOOST_LOG_TRIVIAL): " << duration_cast<milliseconds>(T4 - T3).count() << "ms \n";
    }
    int main()
    {
        Test();
        std::cin.get();
        return 0;
    }
    

    Zurück zu Effiziens des boost Makros:

    Zeit std::err Lösung: 1264ms +- 169,93ms
    Zeit boost Lösung: 3123ms +- 222,55ms

    Ich habe auch versucht das Makro BOOST_LOG_TRIVIAL aufzulösen. Nachdem meine IDE aber nicht alle Makros finden konnte (es kompiliert aber) habe ich es aufgegeben.



  • Bitte ein Bit schrieb:

    ...

    Ich finde, Logging, was sich nicht auf Makro-Ebene ganz wegmachen läßt, brauchste gar nicht zu messen.



  • void WriteToLog(const std::string& Msg)
    {
    #ifdef _DEBUG
        g_pages_mutex.lock();
        //...
        g_pages_mutex.unlock();
    #endif
    }
    

    So besser? :p



  • Bitte ein Bit schrieb:

    void WriteToLog(const std::string& Msg)
    {
    #ifdef _DEBUG
        g_pages_mutex.lock();
        //...
        g_pages_mutex.unlock();
    #endif
    }
    

    So besser? :p

    Nein. Aufrufen tut man es immernoch mit

    WriteLog(whoAmI()+" sends SQL-Command=\"+sql+"\");
    

    und die Funktionsaufrufe und Stingverarbeitung kosten was.

    Also baut man keine ein/aus-schaltbaren Log-Zeilen ein, sondern loggt lieber gar nicht.



  • Ernstgemeint: Ernsthaft?

    Ich dachte bisher der Compiler würde erkennen, dass die aufzurufende Funktion keinen Inhalt hat und sie daher wegoptimieren 😕 😕



  • wooooo schrieb:

    Ernstgemeint: Ernsthaft?

    Ich dachte bisher der Compiler würde erkennen, dass die aufzurufende Funktion keinen Inhalt hat und sie daher wegoptimieren 😕 😕

    In dem Fall natürlich unter der Voraussetzung das whoAmI() "const" ist



  • @Bitte ein Bit
    Miss mal die Performance wenn die Log-Ausgaben zwar mit reincompiliert sind, aber nicht ausgegeben werden (="dynamisch" ausgeschaltet).
    Das ist ein Fall auf den BOOST_LOG speziell hinoptimiert ist.
    Da bleibt nämlich ausser einem "if" nichts mehr übrig -- auch nicht das Auswerten der Expressions die in die Log-Message reingeshiftet werden.

    Wie schnell es dann beim Schreiben ist, ist mir mehr oder weniger egal. (So lange es nicht komplett krass langsam ist.)



  • wooooo schrieb:

    Ernstgemeint: Ernsthaft?

    Ich dachte bisher der Compiler würde erkennen, dass die aufzurufende Funktion keinen Inhalt hat und sie daher wegoptimieren 😕 😕

    Der kann doch nicht wissen, welche Nebeneffekte whoAmI() hat.

    for(int i=0;i<1000000000;++i){//packt er
    }
    
    string fuu;
    for(int i=0;i<1000000000;++i){//weiß nicht, würde mich wundern
       string bar(foo+"test");
    }
    
    for(int i=0;i<1000000000;++i){//klassische optimiererblindmachzeitschleife
       cout<<"";
    }
    


  • hustbaer schrieb:

    Da bleibt nämlich ausser einem "if" nichts mehr übrig -- auch nicht das Auswerten der Expressions die in die Log-Message reingeshiftet werden.

    Wie soll das denn gehen?



  • BOOST_LOG(logger)
            << Expression1
            << Expression2
            ...;
    
    // Wird zu (sinngemäss, stark vereinfacht)
    
        // --BEGIN-- BOOST_LOG(logger)
        if (!IsLoggerEnabled(logger))
            ;
        else
            LogMessage(logger, __FILE__, __LINE__)
        // --END--
            << Expression1
            << Expression2
            ...;
    

    In diesem Beispiel müsste die LogMessage sich selbst im Destruktor selbst loggen. Ich meine sie haben das in Wirklichkeit über nen for -Loop umgesetzt, aber der Teil ist ja diesbezüglich nicht interessant.
    Wichtig ist dass Expression1 , Expression2 etc. nicht ausgewertet werden wenn der Logger nicht aktiv ist.

    (Und man kann Logger auch statisch deaktivieren -- wobei BOOST_LOG dann über Template-Magic dafür sorgt dass IsLoggerEnabled(logger) compile-time-constant wird.)



  • hustbaer schrieb:

    BOOST_LOG(logger)
            << Expression1
            << Expression2
            ...;
    
    // Wird zu (sinngemäss, stark vereinfacht)
    
        // --BEGIN-- BOOST_LOG(logger)
        if (!IsLoggerEnabled(logger))
            ;
        else
            LogMessage(logger, __FILE__, __LINE__)
        // --END--
            << Expression1
            << Expression2
            ...;
    

    In diesem Beispiel müsste die LogMessage sich selbst im Destruktor selbst loggen. Ich meine sie haben das in Wirklichkeit über nen for -Loop umgesetzt, aber der Teil ist ja diesbezüglich nicht interessant.
    Wichtig ist dass Expression1 , Expression2 etc. nicht ausgewertet werden wenn der Logger nicht aktiv ist.

    (Und man kann Logger auch statisch deaktivieren -- wobei BOOST_LOG dann über Template-Magic dafür sorgt dass IsLoggerEnabled(logger) compile-time-constant wird.)

    Was schreibst Du ins Makro FOO, damit bei

    FOO()<<system("cls");
    

    der Systemaufruf nicht passiert?


  • Mod

    volkard schrieb:

    Was schreibst Du ins Makro FOO, damit bei

    FOO()<<system("cls");
    

    der Systemaufruf nicht passiert?

    Könnte so aussehen:
    http://www.c-plusplus.net/forum/p2362104#2362104



  • SeppJ schrieb:

    volkard schrieb:

    Was schreibst Du ins Makro FOO, damit bei

    FOO()<<system("cls");
    

    der Systemaufruf nicht passiert?

    Könnte so aussehen:
    http://www.c-plusplus.net/forum/p2362104#2362104

    Das hat mich jetzt nicht befriedigt.


  • Mod

    volkard schrieb:

    SeppJ schrieb:

    volkard schrieb:

    Was schreibst Du ins Makro FOO, damit bei

    FOO()<<system("cls");
    

    der Systemaufruf nicht passiert?

    Könnte so aussehen:
    http://www.c-plusplus.net/forum/p2362104#2362104

    Das hat mich jetzt nicht befriedigt.

    Wieso? Das erzeugt Code wie den hier:

    FOO()<<system("cls");
    

    ->

    if (true); else Logger << system("cls");
    

    Da wird doch niemals system aufgerufen, da sollte nicht einmal ein (niemals aufgerufener) Aufruf im Code sein, sondern alles komplett wegoptimiert werden.



  • Oh, wie blind von mir!
    thx.



  • SeppJ schrieb:

    ->

    if (true); else Logger << system("cls");
    

    Da wird doch niemals system aufgerufen, da sollte nicht einmal ein (niemals aufgerufener) Aufruf im Code sein, sondern alles komplett wegoptimiert werden.

    Ja.
    Wobei ich den grossen Vorteil eher darin sehe, dass auch mit compile-time aktivem Logger nur Log-Ausgaben, die auch wirklich gemacht werden, merklich bremsen.

    (Der dynamische Test ob ein Logger aktiv ist verwendet bei Boost.Log IIRC nen relaxed atomic load, ist also wirklich sehr billig. Bitte um Korrektur falls es jmd. genauer weiss und ich mich vertan/falsch erinnert habe.)


Anmelden zum Antworten