define und const



  • Hallo Leute,

    ich weiß, dass es einen gewissen Unterschieden der beiden gibt.
    Allerdings weiß ich nicht, ob es schlauer/besser ist, eine constante Variable wie Pi als const double oder über eine define zu definieren.

    Kann mir bitte einer erklären, was besser für Pi geeignet ist?

    Schöne Grüße



  • Serenity schrieb:

    Kann mir bitte einer erklären, was besser für Pi geeignet ist?

    M_PI aus math.h .



  • Oder auch

    [cpp]
    const double pi = 4* atan(1);
    [/cpp]
    


  • Also weder noch beantwortet seine Frage wirklich :S

    @Swordfish: auch wenn viele Standarbibliotheken M_PI beinhalten mögen, so ist es dennoch nicht Teil des ANSI Standards.
    WEnn vorhanden ist es allerdings ein #define

    @Burkhi: Es ist zu bezweifeln, dass 4 * atan(1) ein genauers const double PI liefert als 3.14159265358979323846264338327.
    Daher kann man dann auch gleich den Literal verwenden.
    Da C kein constexpr kennt, dürfte deine Lösung sogar in Runtime-Overhead ausarten, was zwar hier nicht wirklich die Performance runterdrückt, aber man sollte es mal mit sagen :>

    Leider kann ich dir aber auch nicht sagen, was sinnvoller ist.
    Persönlich würde ich zum #define tendieren, da es scheint als wende hier der Compiler black magic an O.o
    Aber darauf würde ich mich nicht stützen. Im Ernstfall dürften beide Varianten zu gleichen Ergebnissen führen und es ist reine Geschmackssache, was man letztendlich verwendet.



  • Serenity schrieb:

    Kann mir bitte einer erklären, was besser für Pi geeignet ist?

    const

    Bzw. ich verwend in dem Fall sowas:

    namespace math
    {
      template <typename T>
      struct constants;
    
      template <>
      struct constants<float>
      {
        static float  one() { return 1.0f; }
        static float zero() { return 0.0f; }
        static float   pi() { return 3.1415926535897932384626434f; }
        static float    e() { return 2.7182818284590452353602875f; }
      };
    
      template <>
      struct constants<double>
      {
        static double  one() { return 1.0; }
        static double zero() { return 0.0; }
        static double   pi() { return 3.1415926535897932384626434; }
        static double    e() { return 2.7182818284590452353602875; }
      };
    
      template <>
      struct constants<long double>
      {
        static long double  one() { return 1.0; }
        static long double zero() { return 0.0; }
        static long double   pi() { return 3.1415926535897932384626434; }
        static long double    e() { return 2.7182818284590452353602875; }
      };
    
    ...
    
    float bla = math::constants<float>::pi();
    }
    

    Damit bekomm ich die jeweilige Konstante immer im richtigen Typ.

    #define verwendet man in C++ jedenfalls nur wenn es sich nicht vermeiden lässt. Das große Problem mit Makros ist, dass sie einfach nur stupide Textersetzung vor dem eigentlichen Kompilieren sind. Dinge wie namespaces interessieren Makros nicht.



  • dot, du hast wohl das Memo nicht bekommen. Im C-Forum sind nur C++-Themen ohne Templates erlaubt.



  • Oh, sry. In dem Fall dann eben einfach nur const 😉



  • dot schrieb:

    #define verwendet man in C++ jedenfalls nur wenn es sich nicht vermeiden lässt. Das große Problem mit Makros ist, dass sie einfach nur stupide Textersetzung vor dem eigentlichen Kompilieren sind. Dinge wie namespaces interessieren Makros nicht.

    C kennt auch keine Namespaces, in sofern ist dieses Argument hinfällig.



  • Mit "namespace" meinte ich nicht unbedingt das C++ Schlüsselwort:

    struct Foo
    {
      int pi;  // hf debugging ;)
    };
    


  • dot schrieb:

    int pi;
    

    Ääääh...



  • Wenn du's so abwegig findest, dann mach ein int* draus...



  • nochmal meine Frage...

    Wir können auch statt Pi die Antwort auf Alles (42) nehmen.
    Die ist sicherlich nicht in irgendeiner Bibliothek drin 😉
    Da sich die Antwort auf alles nicht ändert, ist es besser, diese als globale Variabel const int antwort_auf_alles=42; zu nehmen oder #define ANTWORT_AUF_ALLES 42 ?

    Ich denke, da hat vielleicht jede seine eigenen Bevorzugungen, aber was mich eher interessiert, ist, warum?



  • const int. Begründung siehe oben.



  • Bei Integern würde ich

    enum {
      ANTWORT_AUF_ALLES = 42
    };
    

    schreiben. Das Problem mit Makros ist, dass sie keine Scopes respektieren, also völlig legalen Code zerstören können. Ich hatte grad letztens erst einen Fall, in dem ein Makro genau so hieß wie eine Funktion und der Compiler sich darüber beschwerte, dass er

    static double 100000000() { ... }
    

    übersetzen sollte. So was ist lustig zu debuggen, wenn man nicht alle alten Header auswendig kennt.

    Umgekehrt lassen sich int-Konstanten zumindest in C89 nicht überall verwenden. Beispielsweise ist

    int const ANTWORT_AUF_ALLES = 42;
    int array[ANTWORT_AUF_ALLES]; /* Kawumm. */
    

    dort nicht erlaubt. Da nicht alle gängigen Compiler (hust, MSVC, hust) C99 unterstützen, ist das bis auf weiteres ein Problem.

    enum vereinigt da aus meiner Sicht das beste der beiden Welten.

    Bei Fließkommakonstanten besteht das zweite Problem nicht, also ist da prinzipiell double const besser. Allerdings bin ich mir aus dem Stand nicht sicher, wie es sich da bei den gängigen Compilern mit constant folding während der Optimierung verhält. Wahrscheinlich würde ich

    static double const pi = 3.141592653589; /* Press das mal in einen int, dot. */
    

    schreiben.



  • Mir ist nicht ganz klar was du mit deinem Kommentar bezüglich "in einen int pressen" meinst!?
    Ich hab auch nie was anderes gesagt als const verwenden 😕
    Mein Beispiel mit dem int diente genau dazu, das von dir mittlerweile ebenfalls erwähnte Problem von Makros vs. Scope zu illustieren...



  • Naja, Pi als int (also als Ganzzahl) darstellen zu wollen, hat schon etwas merkwürdiges.

    Übrigens, was die Scope-Geschichte angeht - auch

    struct Foo {
      double pi;
    };
    

    funktioniert nicht wirklich gut als Namensraum, und static geht in C ja an dieser Stelle nicht. Man könnte womöglich

    static struct {
      double one;
      double zero;
      double pi;
      double e;  
    } const math_constants = {
      1.0,
      0.0,
      3.1415926535897932384626434,
      2.7182818284590452353602875
    };
    
    double circle_area(double radius) {
      return 2 * math_constants.pi * radius;
    }
    

    schreiben, aber die Funktionalität ist gegenüber echten Namensräumen, wie man sie von C++ kennt, natürlich stark eingeschränkt, und ob man jetzt MATH_CONSTANTS_PI oder math_constants.pi da stehen hat, ist letztendlich ohne Bedeutung.



  • Einzig der Vorteil bei Strukturen ist, dass man die einzelnen Konstanten und Namen nicht auswendig kennen muss. Kennt man den Structurnamen, werden einem (je nach Entwicklungsumgebung) die darin enthaltenen Elemente angezeigt. Aber dies ist rein gesehen eine sache des Komforts 😉

    Mir wurde damals im ersten Jahr Programmieren reingedrückt, ich solle Makros (Problemstellung wurde oben genannt) mit Vorsicht genießen. Daher verwende ich für PI ne globale Variable vom Typ const double. Auf Define greife ich in VC nur für die Länge der statischen Arrays zu, da es nicht
    immer nötig ist solche Dynamisch auf dem Heap anzulegen 😉



  • seldon schrieb:

    Naja, Pi als int (also als Ganzzahl) darstellen zu wollen, hat schon etwas merkwürdiges.

    Wir reden aneinander vorbei, darum gings nie. Das Beispiel mit dem struct sollte zeigen was passiert wenn du ein #define pi hast und dann irgendo sonst im Programm der Bezeichner pi vorkommt. Mach einen int* draus und du hast gern mal irgendwo ein pi, nicht wegen dem griechischen Buchstaben, sondern z.B. wegen ungarischer Notation (um weiteren Missverständnissen vorzubeugen: Nein die empfehle ich nicht)...



  • DrakoXP schrieb:

    Also weder noch beantwortet seine Frage wirklich :S

    @Swordfish: auch wenn viele Standarbibliotheken M_PI beinhalten mögen, so ist es dennoch nicht Teil des ANSI Standards.

    Echt ned?

    In dem Fall nimmst ein const double mit sinnigem Namen und und irgendeinen Wert, der in richtung pi geht 🤡


Anmelden zum Antworten