Haben diese Defines irgendeinen Sinn?


  • Mod

    Die Namen sind für die Implementation reserviert.

    Nein, das sind sie nicht. Nicht jeder Name, der mit einem Unterstrich beginnt, ist reserviert.

    Mit viel gutem Willen könnte man vermuten dass es ein äußerst miserabler Versuch war den Code zwischen C und C++ kompatibel zu halten.

    Und wie ist das Fehler-Behandeln geregelt?



    • schrieb:

    Die Namen sind für die Implementation reserviert.

    Nein, das sind sie nicht. Nicht jeder Name, der mit einem Unterstrich beginnt, ist reserviert.

    *facepalm*


  • Mod

    Ist natürlich Unsinn.
    Vor allem, weil es sogar genauso definiert ist:

    Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.


  • Mod

    • schrieb:

    Und wie ist das Fehler-Behandeln geregelt?

    Man könnte für C++ das Makro natürlich so definieren

    #define _new(T) new (std::nothrow_t)T
    

    Allerdings ist das ab dem Punkt Blödsinn, wo nicht triviale Klassen im Spiel sind.
    In C gibt es das natürlich nicht. Nun, dann klappt das sogar.



    • schrieb:

    Ist natürlich Unsinn.

    Der grösste Unsinn ist, dass du ständig den Inhalt deiner Posts völlig umänderst. Das regt mich auf. Das ist unredlich, wie jemand anders mal gesagt hat.

    Wenn du was geschrieben hast, warte 10sec bevor du den Absenden-Button drückst und frage dich, ob das Sinn macht, was du schreibst.

    Wenn du erst im Nachhinein merkst, dass das Schwachsinn ist, dann lass den Text, aber streich ihn durch.

    Im Editieren ist nur einer der folgenden Züge erlaubt:
    1. Ortographiefehler beheben.
    2. Sachen durchstreichen.
    3. Ganz am Schluss ein "Edit: <neuer Text>" hinzufügen.
    Halte dich mal eine Woche oder so ausnahmslos dran.

    Irren ist menschlich, aber steh zu deinen Fehlern. So führt das nur zu Diskussionen, die nicht nachvollziehbar sind.


  • Mod

    Gut, das nehme ich mir vor - Post ist gestrichen.

    Irren ist menschlich, aber steh zu deinen Fehlern.

    Das stand da buchstäblich mehrere Sekunden!



  • Hallo, ob des akuten Frustes über einen Quellcode den ich neuprogrammieren darf (da der alte unfassbar grausam schlecht ist, kA wer den verbrochen hat):

    Hat das hier IRGENDEINEN praktischen Sinn?!

    C++:
    #define _new(t) ((t*)malloc(sizeof(t)))
    #define _new_array(t, n) ((t*)malloc(sizeof(t) * (n)))
    #define _resize_array(a, t, n) ((t*)realloc((a), sizeof(t) * (n)))
    #define _size_array(a,t,n0,n1) a = (n0 == 0 ? _new_array(t,n1) : \
    _resize_array(a,t,n1))
    #define _delete(object) ((void)(((object)!=NULL) ? \
    free((char*)(object)),(object)=NULL : 0))

    Natürlich genuzt in deinem C++-Projekt...

    Gott macht mich das grade wütend

    Für mich macht solchen Code keine Sinn, außer dass ein C Programmierer versucht C++ zu programmieren.

    Der Code strotzt vor Fehlerquellen / Seiteneffekten uns sollte verbessert werden.

    Und bitte: Keine Makro's!!!



  • @Bitte ein Bit
    > Und bitte: Keine Makro's!!!

    Wieso nicht?

    Makros sind doch in C perfekt dafür. Bzw. die einzige Möglichkeit - Templates gibt's ja nicht. Worüber man streiten kann sind die Seiteneffekte.
    Andrerseits hast du die in C++ genau so, wenn irgendwo mit "non-const" Referenzen wird.



  • Makros sind doch in C perfekt dafür. Bzw. die einzige Möglichkeit - Templates gibt's ja nicht.

    Ja in C vieleicht. Aber selbst hier würde ich nur ganz einfache Makro's benutzen, weil diese unter anderem nicht debugbar sind.

    Da wir hier aber in der C++ Abteilung sind, stellt sich hier nicht die Frage nach C.

    Worüber man streiten kann sind die Seiteneffekte.

    #define _new(t) ((t*)malloc(sizeof(t)))
    #define _new_array(t, n) ((t*)malloc(sizeof(t) * (n)))
    #define _resize_array(a, t, n) ((t*)realloc((a), sizeof(t) * (n)))
    #define _size_array(a,t,n0,n1) a = (n0 == 0 ? _new_array(t,n1) : \
    _resize_array(a,t,n1))
    #define _delete(object) ((void)(((object)!=NULL) ? \
    free((char*)(object)),(object)=NULL : 0)) 
    
    #define _resize_array2(a, t, n) (realloc((a), sizeof(t) * (n)))
    class A
    {
        int a;
    public:
        A() : 
          a(-1)
        {}
    };
    int main(int argc, char** argv)
    {
        A* MyA;
        char* a;
        unsigned char NewSize = 5;
    
        // Warum ist hier MyA() nicht -1???
        MyA = _new(A);
        // Was mache ich hier falsch? Und wie debugge ich das?
        _size_array(a, char, 0, 5) + 1;
        (_size_array(a, char, 0, 5)) = 0;
        _resize_array2(a, 2, 5);
        _size_array(a, char, 3, 5) + 1;
        _size_array(a, char, 3, ++NewSize) + 1;  // Der Klassiker unter den Beispielen!
        return 0;
    }
    

    Wie du oben siehst, ist es mit diesen Makro Funktionen relativ leicht schwer auffindbare Fehler zu produzieren. Bekomme das mal mit std::vector hin!

    Spiel doch einfach mal destruktiver DAU und versuche den Code zum Absturz zu bewegen!

    Andrerseits hast du die in C++ genau so, wenn irgendwo mit "non-const" Referenzen wird.
    

    Wären wir hier bei Templates würde ich davon sprechen das die Typsicherheit als auch das Konzept (Bsp.: DefaultConstructible) fehlt.

    Wir sollten mal einen kleinen Wettbewerb versuchen. Wir sollten eine einfache Aufgabe mittels Makro und (inline) Funktion lösen und jeweils versuchen sie einfach und sicher bedienbar zu machen, s.d. bei allen Eingaben immer etwas sinnvolles herauskommt.

    Wetten: Makros unterliegen?


  • Mod

    Bitte ein Bit: Das habe ich oben bereits festgestellt, dass das bei Klassen* in C++ nicht funktioniert. Es ist sogar undefiniertes Verhalten, mit dem gecasteten Zeiger irgendwelche Memberfunktionen aufzurufen o.ä.

    Edit:

    Da wir hier aber in der C++ Abteilung sind, stellt sich hier nicht die Frage nach C.

    Offensichtlich ist aber der Code (für oder mit) C geschrieben. Mit Klassen* darf man das nicht mischen.

    • ~mit nicht-trivialen Klassen.~


  • Bitte ein Bit schrieb:

    Makros sind doch in C perfekt dafür. Bzw. die einzige Möglichkeit - Templates gibt's ja nicht.

    Ja in C vieleicht. Aber selbst hier würde ich nur ganz einfache Makro's benutzen, weil diese unter anderem nicht debugbar sind.

    Das ist ja auch ganz eindeutig C Code.

    Wir sollten eine einfache Aufgabe mittels Makro und (inline) Funktion lösen und jeweils versuchen sie einfach und sicher bedienbar zu machen, s.d. bei allen Eingaben immer etwas sinnvolles herauskommt.

    Wetten: Makros unterliegen?

    Wenn ich die Anforderungen festlegen kann dann gewinnen sicher Makros, weil ich dann nämlich Sachen auswähle die man mit Inline-Funktionen einfach nicht (oder nicht sinnvoll) machen kann 😉
    Deren gibt es in C extrem viele, aber auch in C++ ist noch einiges übrig.



  • Das ist ja auch ganz eindeutig C Code.

    Das _new() Makro sieht aber ein wenig nach C/C++ Mischmasch aus. Ein C Programmierer würde nämlich den Cast nach (t*) weglassen. Unter C++ wirft mein Compiler mir einen Fehler um die Ohren. 😉

    #define _new(t)         ((t*)malloc(sizeof(t)))
    

    Wenn ich die Anforderungen festlegen kann dann gewinnen sicher Makros, weil ich dann nämlich Sachen auswähle die man mit Inline-Funktionen einfach nicht (oder nicht sinnvoll) machen kann

    Kannst du mir mal ein Beispiel geben?



  • Bitte ein Bit schrieb:

    Wenn ich die Anforderungen festlegen kann dann gewinnen sicher Makros, weil ich dann nämlich Sachen auswähle die man mit Inline-Funktionen einfach nicht (oder nicht sinnvoll) machen kann

    Kannst du mir mal ein Beispiel geben?

    Logging.



  • Logging.

    Aufgrund dieser Information rate ich mal ins Blaue und vermute du meinst Boost:

    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    

    Naja, schau dir mal die Implementierung an.

    #define BOOST_LOG_UNIQUE_IDENTIFIER_NAME_INTERNAL_(prefix, postfix)\
        BOOST_PP_CAT(prefix, postfix)
    #define BOOST_LOG_UNIQUE_IDENTIFIER_NAME_INTERNAL(prefix, postfix)\
        BOOST_LOG_UNIQUE_IDENTIFIER_NAME_INTERNAL_(prefix, postfix)
    
    #if BOOST_WORKAROUND(BOOST_MSVC, >=1300)
    #  define BOOST_LOG_UNIQUE_IDENTIFIER_NAME(prefix)\
        BOOST_LOG_UNIQUE_IDENTIFIER_NAME_INTERNAL(prefix, __COUNTER__)
    #else
    #  define BOOST_LOG_UNIQUE_IDENTIFIER_NAME(prefix)\
        BOOST_LOG_UNIQUE_IDENTIFIER_NAME_INTERNAL(prefix, __LINE__)
    #endif
    
    #define BOOST_LOG_STREAM_INTERNAL(logger, rec_var)\
        for (::boost::log::record rec_var = (logger).open_record(); !!rec_var;)\
            ::boost::log::aux::make_record_pump((logger), rec_var).stream()
    
    #define BOOST_LOG_STREAM_WITH_PARAMS(logger, params_seq)\
        BOOST_LOG_STREAM_WITH_PARAMS_INTERNAL(logger, BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_record_), params_seq)
    
    #define BOOST_LOG_TRIVIAL(lvl)\
        BOOST_LOG_STREAM_WITH_PARAMS(::boost::log::trivial::logger::get(),\
            (::boost::log::keywords::severity = ::boost::log::trivial::lvl))
    

    Ist ja alles Gut und schön. Aber wenn ein Fehler in dem Makro ist, hast du ein ernsthaftes und unnötiges Debugging Problem.

    Typischer Write-Only Code...



  • Richtig geraten.

    Bitte ein Bit schrieb:

    Ist ja alles Gut und schön. Aber wenn ein Fehler in dem Makro ist, hast du ein ernsthaftes und unnötiges Debugging Problem.

    Ist die Implementierung unschön zu lesen? Ja.
    Ist es lästig zu debuggen? Ja.
    Ist die Implementierung unmöglich zu verstehen? Nein.
    Ist die Implementierung unmöglich zu debuggen? Nein.

    Ist es schweinepraktisch? Ja.

    Ich mag schweinepraktische Sachen. Zeig mir eine Implementierung mit Inline-Funktionen die ähnlich performant ist und ähnlich schöne Syntax erlaubt.

    Typischer Write-Only Code...

    Das ist schwer übertrieben.
    Davon abgesehen: was für einen Grund sollte es geben da grossartig was dran zu ändern? Notfalls ist die gesamte Implementierung klein genug dass man sie einfach komplett neu schreiben kann.

    Und wenn du das schon schlimm findest, dann darfst du auch niemals irgendwo Regexen verwenden.



  • Makros sind manchmal wahnsinnig praktisch. Einige moderne Sprachmittel wurden vor C++11 mit Makros emuliert.

    • Range-Based For Loop: Boost.Foreach
    • RValue-Referenzen: Boost.Move
    • Variadic Templates: Boost.Preprocessor

    Aber das rechtfertigt natürlich noch lange keinen Code wie _new von diesem Thread...



  • @Nexus
    Das _new Makro in diesem Thread hat mMn. ganz klar den Sinn Code zwischen C und C++ kompatibel zu halten. Und das ohne überall bei malloc manuell die Casts schreiben zu müssen.
    Über den Namen kann man streiten, über einige der anderen Makros auch, aber grundsätzlich finde ich es eine sehr gute Lösung.

    Manuell hundertfach in einem Projekt

    var = (Foo*)malloc(sizeof(Foo));
    

    zu schreiben ist sicher nicht die Lösung. Böse DRY Verletzung.



  • hustbaer schrieb:

    Das _new Makro in diesem Thread hat mMn. ganz klar den Sinn Code zwischen C und C++ kompatibel zu halten.

    Dazu überlädt man operator new und operator delete.


  • Mod

    operator delete schrieb:

    hustbaer schrieb:

    Das _new Makro in diesem Thread hat mMn. ganz klar den Sinn Code zwischen C und C++ kompatibel zu halten.

    Dazu überlädt man operator new und operator delete.

    Und wie überlädt man einen Operator in C?



  • Arcoth schrieb:

    Ist natürlich Unsinn.
    Vor allem, weil es sogar genauso definiert ist:

    Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

    Höh? Doch nur wenn der Name __ als Prefix hat bzw. ein Großbuchstabe dem _ folgt?


Anmelden zum Antworten