C-Style cast -> statich_cast<>()



  • Hier gleich meine zweite Frage an die Gemeinschaft:

    Ich habe im Code folgendes stehen:

    int now = 3, total = 10;        
    double progress = (double)now / (double)total;
    

    Ich würde das gerne umwandeln:

    int now = 3, total = 10;    
    double progress = static_cast<double>(now / total);
    

    Die Frage ist, ob die Division nun 3 oder 3,3333… ergibt?
    Die Variablen now und total werden vorher bestimmt:

        const char *p = bar + 1;
        bool isProgressbar = true;
        int total = 0;
        int now = 0;
        for (; *p != ']'; ++p) {
            if (*p == ' ' || *p == '|') {
                ++total;
                if (*p == '|')
                    ++now;
            } else {
                isProgressbar = false;
                break;
            }
        }
    
    

    Im Beispiel oben hab ich die mal gesetzt zum Verständnis.



  • @MegaV0lt
    Probier's doch einfach aus. Die Gemeinschaft ist kein Compiler, und deine Frage ist doch wirklich einfach selbst zu beantworten.


  • Mod

    @DocShoe sagte in C-Style cast -> statich_cast<>():

    @MegaV0lt
    Probier's doch einfach aus. Die Gemeinschaft ist kein Compiler, und deine Frage ist doch wirklich einfach selbst zu beantworten.

    Weitere wichtige Übung für dich selbst: Welches Ergebnis würdest du warum erwarten? Denk darüber genau nach! Nimm die beiden Ausdrücke (double)now / (double)total und static_cast<double>(now / total) auseinander und versuch sie zu verstehen! Der Computer ist keine magische Maschine, die irgendwie grob was macht, was mit den Worten im Quelltext zu tun hat. Er folgt ganz strikt einem Regelwerk, das man verstehen kann/muss.



  • Es gibt an der Stelle keinen Grund für einen Cast, weil man mit Conversion problemlos zurecht kommt.

    Also anstatt

    double progress = (double)now/(double)total;
    

    lieber so

    double progress = double(now)/double(total);
    

  • Mod

    Dieser Beitrag wurde gelöscht!


  • @john-0 sagte in C-Style cast -> statich_cast<>():

    lieber so
    double progress = double(now)/double(total);

    Das ist kein Cast?


  • Mod

    @MegaV0lt sagte in C-Style cast -> statich_cast<>():

    @john-0 sagte in C-Style cast -> statich_cast<>():

    lieber so
    double progress = double(now)/double(total);

    Das ist kein Cast?

    Technisch gesehen Nein, aber der Unterschied ist rein syntaktisch. Es sind zwei neue doubles, die mit den Werten von now und total initialisiert werden, wozu diese Werte dann wiederum erst implizit als doubles interpretiert werden. Im Gegensatz zum Cast, wo diese Werte direkt explizit als double interpretiert werden. Ich weiß auch nicht, was john-0 dir damit sagen will. Beides nutzt die implizite Konvertierbarkeit von int nach double, genauso wie dein C++-style static_cast. Noch eine Möglichkeit, die implizit int nach double konvertiert: 1.0 * now / total. Such dir selber aus, welche Schreibweise du für die nützlichste hältst.

    Letztlich wird der Compiler aber den gleichen Code für alles erzeugen.

    PS: Und falls du es bis jetzt nicht selbst gemerkt hast: static_cast<double>(now / total) ist wahrscheinlich nicht das, was du meintest. Denn da wird der Cast nach double ja auf das Ergebnis von now/total angewandt. D.h. da passiert erst eine Ganzzahldivision mit Ganzzahlergebnis (im Typensinne), und das als double zu interpretieren, ändert nichts daran, dass das eine Ganzzahl ist (im mathematischen Sinne). Du willst den Cast auf (mindestens) eine Hälfte der Division anwenden, bevor diese passiert, nicht auf das Ergebnis.



  • Ok, bekomme allerdings mit

    double(now)
    

    Auch eine Warnung, dass die Syntax veraltet ist
    Nach einigem "Googeln", werde ich das wohl so machen:

    double progress = now * 1.0 / total;
    

    Edit: Gerade gesehen @SeppJ hat es ja auch so vorgeschlagen 😉


  • Mod

    Ich habe dir auch oben noch eine Erklärung gegeben, was an static_cast<double>(now / total) falsch ist, während du schon geantwortet hast.



  • @SeppJ sagte in C-Style cast -> statich_cast<>():

    Im Gegensatz zum Cast, wo diese Werte direkt explizit als double interpretiert werden. Ich weiß auch nicht, was john-0 dir damit sagen will.

    Man sollte in C++ die Konversion dem Cast vorziehen, wenn es dabei zu keinem Datenverlust kommt. Casts sind etwas besonders, und signalisieren, dass z.B. Informationen verloren gehen können. Wenn man nun jede x-beliebige Typkonversion mit einem Cast verdeckt, dann weist man der Aktion eine Bedeutung zu, die sie nicht hat. Nur ist der static_cast nicht wirklich geeignet an dieser Stelle, da er Grunde nichts besser macht. Aber es gibt immerhin beim Boost Projekt ein passenden Cast für diese Möglichkeit.

    Leider gehört das Themengebiet zu den C Altlasten in C++, so dass das nicht so funktioniert wie es wünschenswert wäre.

    #include <iostream>
    #include <cstdlib>
    #include <boost/numeric/conversion/cast.hpp>
    
    int main() {
        int x = 100000;
        short s1 = 0, s2 = 0, s3 = 0;
    
        double d = double(x);
        s1 = static_cast<short>(x);
        s2 = x;
    
        std::cout << x << "\n";
        std::cout << d << "\n";
        std::cout << s1 << ", " << s2 << "\n";
    
        try {
            s3 = boost::numeric_cast<short>(x);
    
            std::cout << s3 << "\n";
        }
        catch (std::exception& e) {
            std::cerr << "conversion failed\n";
            std::cerr << e.what();
        }
    
        return EXIT_SUCCESS;
    }
    


  • @SeppJ sagte in C-Style cast -> statich_cast<>():

    @MegaV0lt sagte in C-Style cast -> statich_cast<>():

    @john-0 sagte in C-Style cast -> statich_cast<>():

    lieber so
    double progress = double(now)/double(total);

    Das ist kein Cast?

    Technisch gesehen Nein, [...]

    Ich glaube schon, dass das ein Cast ist. Nennt sich functional-style cast expression, siehe Explicit type conversion, Syntax-Variante (2):

    If there is exactly one expression in parentheses, this cast expression is exactly equivalent to the corresponding C-style cast expression.

    Hab das auch lange Zeit wie einen Konstruktor gelesen. Aber wie man auch immer es nennt, am Ende kommt eh dasselbe bei raus, spätestens nach Optimierungen 😄



  • @SeppJ sagte in C-Style cast -> statich_cast<>():

    @MegaV0lt sagte in C-Style cast -> statich_cast<>():

    @john-0 sagte in C-Style cast -> statich_cast<>():

    lieber so
    double progress = double(now)/double(total);

    Das ist kein Cast?

    Technisch gesehen Nein, aber der Unterschied ist rein syntaktisch. Es sind zwei neue doubles, die mit den Werten von now und total initialisiert werden, wozu diese Werte dann wiederum erst implizit als doubles interpretiert werden. Im Gegensatz zum Cast, wo diese Werte direkt explizit als double interpretiert werden.

    Das ist eine "functional-style cast expression", und diese ist für eingebaute Typen vom Verhalten her equivalent zum C-style cast.

    Siehe https://en.cppreference.com/w/cpp/language/explicit_cast (2)

    D.h. die Umwandlung ist sehr "explizit", man kann damit schliesslich auch z.B. Integers in Zeiger verwandeln - was mit impliziten Umwandlungen ja nicht geht. Für impliziten Umwandlung ist mir keine "inline" Schreibweise bekannt.

    ps: Upps, das wurde ja gerade schon geschrieben. Aber löschen tu ich meins deswegen auch nicht 🙂



  • @Finnegan sagte in C-Style cast -> statich_cast<>():

    Hab das auch lange Zeit wie einen Konstruktor gelesen. Aber wie man auch immer es nennt, am Ende kommt eh dasselbe bei raus, spätestens nach Optimierungen 😄

    Naja, der grosse Unterschied ist dass es halt ein C-style cast, aka. "halt die Klappe und mach es einfach" ist. Man kann damit also viel mehr Unsinn bauen als mit z.B. Type{expression} oder static_cast<Type>(expression).



  • @DocShoe sagte in C-Style cast -> statich_cast<>():

    @MegaV0lt
    Probier's doch einfach aus. Die Gemeinschaft ist kein Compiler, und deine Frage ist doch wirklich einfach selbst zu beantworten.

    Weil ich es nirgendwo erwähnt sah; @MegaV0lt , mach Dich mal mit einem Debugger vertraut. Da kannst Du i.d.R. die Werte der einzelnen Variablen überprüfen.



  • @hustbaer sagte in C-Style cast -> statich_cast<>():

    @Finnegan sagte in C-Style cast -> statich_cast<>():

    Hab das auch lange Zeit wie einen Konstruktor gelesen. Aber wie man auch immer es nennt, am Ende kommt eh dasselbe bei raus, spätestens nach Optimierungen 😄

    Naja, der grosse Unterschied ist dass es halt ein C-style cast, aka. "halt die Klappe und mach es einfach" ist. Man kann damit also viel mehr Unsinn bauen als mit z.B. Type{expression} oder static_cast<Type>(expression).

    Etwas späte Antwort, aber da stimme ich zu. Würde sich das - wie man es intuitiv erstmal liest - wie ein T(T)-Konstruktor verhalten, dann wäre das unterm Strich wie ein static_cast. Das würde daher nicht nur "Unsinn" vermeiden, wie du schreibst, sondern wäre auch irgendwie konsistenter, wenn es lediglich eine alternative Syntax für static_cast wäre.



  • @Finnegan Ich hab ehrlich gesagt auch lange Zeit gedacht dass es sich wie static_cast verhält. Und ich habe festgestellt dass ich damit nicht alleine bin. Viele C++ Entwickler, auch erfahrene, glauben dass es equivalent zu static_cast ist. Und so lange man nur Dinge damit castet die auch mit static_cast gehen, ist es ja auch so.

    Würde sich das - wie man es intuitiv erstmal liest - wie ein T(T)-Konstruktor verhalten, dann wäre das unterm Strich wie ein static_cast.

    Ich gehe mal davon aus dass du einen T(T const&) bzw. T(T&&) Konstruktor meinst.
    Und da verhält sich static_cast schon anders, zumindest bei Zeigern. Denn da kannst du mit static_cast ja auch Downcasts machen bzw. auch von void* zu T* konvertieren.

    Die sicherste explizite Konvertierung ist T{expression}. Da sind z.B. auch "narrowing conversions" verboten. Obwohl GCC hier nur eine Warnung ausgibt (Clang, MSVC: Fehler). Wobei ich glaube dass das Verhalten von GCC standardkonform ist. Der Standard schreibt oft gar kein Verhalten bei "verbotenen" Dingen vor, und wenn, dann meistens nur dass es eine "diagnostic" geben muss. Und das ist auch mit einer Warnung erfüllt.


  • Mod

    @hustbaer sagte in C-Style cast -> statich_cast<>():

    Wobei ich glaube dass das Verhalten von GCC standardkonform ist. Der Standard schreibt oft gar kein Verhalten bei "verbotenen" Dingen vor, und wenn, dann meistens nur dass es eine "diagnostic" geben muss. Und das ist auch mit einer Warnung erfüllt.

    Klar. Es ist aber auch irgendwie seltsam, dass GCC sich entscheidet, narrowing conversions zuzulassen, was anmutet wie eine Entscheidung um legacy Code zu unterstützen, wohingegen diese Syntax zum Zeitpunkt jener Entscheidung noch sehr jung gewesen sein muss. Ich bin mittlerweile auch u.a. diesem Grund einfach ein grösserer Fan von Clang. Move fast & break things 😉

    Was mich an dem Zustand der Syntax stört, ist auch die Tatsache, dass C-Style casts so viel einfacher zu tippen sind (ich hab keinen Bock static_cast<> auszuschreiben). Aber das sind eben diese historischen Tumore, die man nicht mehr exzisieren kann...



  • @Columbo sagte in C-Style cast -> statich_cast<>():

    Klar. Es ist aber auch irgendwie seltsam, dass GCC sich entscheidet, narrowing conversions zuzulassen,

    Ich sehe zu, dass auch alle Warnungen bei eigenem Code entfernt werden. Insofern macht das für mich keinen großen Unterschied, ob das nun Warnungen oder Fehler sind. Zudem existiert das Compiler-Flag "-Werror".

    Was mich an dem Zustand der Syntax stört, ist auch die Tatsache, dass C-Style casts so viel einfacher zu tippen sind (ich hab keinen Bock static_cast<> auszuschreiben).

    C Casts sind aber immer die gleichen, und unterscheiden nicht nach den für C++ notwendigen Fällen.


Anmelden zum Antworten