Stilfrage: Globale Konstanten



  • HighLigerBiMBam schrieb:

    In der Regel kannst du globale Variablen bei gutem Design vermeiden.

    Das sind Konstanten und keine Variablen. Und ich sehe keinen Grund warum man die vermeiden sollte.

    Und noch ein Tipp: Versuche Konstanten aus einer Datei auszulesen, dann kannst du diese ändern ohne dein Programm immer neu erstellen zu müssen.

    Konstanten die sich nie ändern können (wie die Anzahl der Bytes in einem MB) aus einer Datei auslesen, ist also besser, also ein paar Byte für ein paar mickrige Konstanten zu "verschwenden". Die der Compiler übrigens eh verwerfen wird, da sie nicht gebraucht werden.

    @Trial:
    Mach deine Konstanten static , dann sollte der Compiler ruhe geben.



  • Oder wie wär's mit externen Konstanten:

    //Constants.h
    extern const int i_1KB;
    //...
    
    //Constants.cpp
    #include "Constants.h"
    const int i_1KB = 1000;
    //...
    


  • @wxSkip: Das ist aber schon verarsche oder? Wenn nicht, wozu soll DAS bitte gut sein?



  • Also Konstanten für 1.e9, size_t(1.e9) und size_t(1)<<30 halte ich für unnötig.
    Ich würde beim Lesen an d_1GB mehr Zeit verleren, fürchte ich.
    Aber wenn es denn unbedingt sein muß, mach halt.
    Aber bitte ohne extern, Makros, Laufzeit-Datei und so Sachen.



  • theliquidwave schrieb:

    @wxSkip: Das ist aber schon verarsche oder? Wenn nicht, wozu soll DAS bitte gut sein?

    Eigentlich zu nichts, außer:
    1. Die Konstanten sollten sich mal ändern (was hier höööchstwahrscheinlich nicht vorkommen wird)
    2. Der Compiler meckert nicht mehr 😉
    3. Das Programm hat mehr Zeilen und die Statistik schaut besser aus 😃



  • 4. Man kann sie nicht mehr als Template-Parameter benutzen.

    Punkt 3 lässt mich vermuten, dass du deine Berufswahl nochmal überdenken solltest. Marketing wäre eine Möglichkeit, sofern du ohne Seele auskommst.



  • Man kann das ganze auch in ein enum packen. Damit wird dann auch kein Speicher belegt. Nachteil ist, jede Konstante darf nur einmal im enum vorkommen. Du kannst aber beliebig viele enums anlegen.



  • Nick Unbekannt schrieb:

    Nachteil ist, jede Konstante darf nur einmal im enum vorkommen.

    Laut dem C++ Standard ist das erlaubt.



  • seldon schrieb:

    4. Man kann sie nicht mehr als Template-Parameter benutzen.

    Punkt 3 lässt mich vermuten, dass du deine Berufswahl nochmal überdenken solltest. Marketing wäre eine Möglichkeit, sofern du ohne Seele auskommst.

    😃 🤡



  • Weshalb enum , wenn man keinen Aufzählungstypen definieren will? Nimm einfach const für Konstanten. Wenn du keinen antiken Compiler hast, benötigen die auch keinen Speicherplatz.

    hustbaer schrieb:

    Mach deine Konstanten static , dann sollte der Compiler ruhe geben.

    Wieso das? An der Linkage ändert es nämlich nichts.



  • Nexus schrieb:

    hustbaer schrieb:

    Mach deine Konstanten static , dann sollte der Compiler ruhe geben.

    Wieso das? An der Linkage ändert es nämlich nichts.

    Haste auch wieder recht.
    Ich hab' die Warning einfach nur abgedreht, DAS wird der Grund sein warum er bei mir nicht meckert 😃



  • Nexus schrieb:

    Weshalb enum , wenn man keinen Aufzählungstypen definieren will? Nimm einfach const für Konstanten. Wenn du keinen antiken Compiler hast, benötigen die auch keinen Speicherplatz.

    Was auch nur funktioniert, wenn man keine so-Files erstellen will.

    Was mir aber noch auffällt und noch gar nicht angesprochen wurde. Wenn ich Konstanten allgemein definiere, dann will ich die unter Umständen mehrmals verwenden und dann würdest du mit dieser const-Variante im Header an die Grenzen stoßen. Da nützen dir dann auch deine inclusion guards nichts mehr.



  • Nick Unbekannt schrieb:

    Nexus schrieb:

    Weshalb enum , wenn man keinen Aufzählungstypen definieren will? Nimm einfach const für Konstanten. Wenn du keinen antiken Compiler hast, benötigen die auch keinen Speicherplatz.

    Was auch nur funktioniert, wenn man keine so-Files erstellen will.

    Was mir aber noch auffällt und noch gar nicht angesprochen wurde. Wenn ich Konstanten allgemein definiere, dann will ich die unter Umständen mehrmals verwenden und dann würdest du mit dieser const-Variante im Header an die Grenzen stoßen. Da nützen dir dann auch deine inclusion guards nichts mehr.

    Echt? Erzeugen die Speicher?



  • so-Files?

    Unter Linux werden alle Symbole exportiert. Man kann über Attribute im GCC die Sichtbarkeit einschränken, dass ist dann aber nicht mehr portabel. Und funktioniert auch nur in jüngeren Versionen, soweit ich mich entsinne.



  • volkard schrieb:

    Erzeugen die Speicher?

    Schön wärs... Leider verbrauchen sie Speicher.
    Zum Glück ist das jedoch nur der Fall, wenn man irgendwo aus Unachtsamkeit ein & vor die Konstante schreibt.

    Nick Unbekannt schrieb:

    Unter Linux werden alle Symbole exportiert.

    Bei mir nicht. Kontrolliert mit

    $ g++ -c --optimize a.cc -o a.o
    $ ld -G a.o -o liba.so
    $ nm liba.so
    000011c8 a _DYNAMIC
    00001240 a _GLOBAL_OFFSET_TABLE_
    00000188 T _Z10do_nothingv
    0000124c A __bss_start
             U __gxx_personality_v0
    0000124c A _edata
    0000124c A _end
    $ rm a.cc a.o liba.so
    


  • Woher weiß dein Linker, welche Symbole nicht benötigt werden?

    Das könnte sehr interessant dazu sein: http://gcc.gnu.org/wiki/Visibility



  • Es ist nicht der Linker, sondern der Compiler. Ohne --optimize sind alle Konstanten vorhanden.



  • Das funktioniert aber nur, wenn du irgendwie das Symbol aus der globalen Sichtbarkeit raus nimmst. Der Compiler kann keine Symbole weg optimieren, die global sichtbar sind. Ist ja auch logisch, er sieht nur das eine Objektfile.



  • Nick Unbekannt schrieb:

    Was mir aber noch auffällt und noch gar nicht angesprochen wurde. Wenn ich Konstanten allgemein definiere, dann will ich die unter Umständen mehrmals verwenden und dann würdest du mit dieser const-Variante im Header an die Grenzen stoßen. Da nützen dir dann auch deine inclusion guards nichts mehr.

    Verstehe ich grad nicht.
    Default ist für Daten internal linkage ("static"), worauf mich Nexus netterweise hingewiesen hat.
    Wieso sollte das dann ein Problem mit SOs geben?

    Und falls das wirklich ein Problem gibt sind SOs scheisse 😃

    Ne, im Ernst, das muss gehen. Das verwenden SO viele Projekte...



  • Ist eigentlich recht einfach. Das Shared-Object-File ist im Prinzip nichts anderes, als wie jedes andere Object-File. Dass heißt für den Linker werden die Symbole die global sind exportiert. Durch das dynamische Binden ist es aber nicht klar, welche Symbole nun wirklich benötigt werden. Somit gibt es erstmal keine nicht verwendeten Symbole, die entfernt werden können. Streng genommen wären alle Symbole nicht verwendet, in dem Moment. Dem Linker dürfte es dabei sogar ziemlich egal sein, ob es sich um Daten oder Code handelt, er verknüpft letztendlich nur die Symbole. Schlimm ist dieses Verhalten nicht unbedingt, da man die Sichtbarkeit auch einschränken kann. Unter Windows verfolgt man den Ansatz, dass die Symbole explizit exportiert werden müssen. Damit ist dann auch das von dir bevorzugte Verhalten anwendbar.
    Davon abgesehen kommt es trotzdem zum Konflikt, wenn ich Konstanten im Header definiere und diesen in mehreren Object-Files einbinde. Auch wenn die Mehrfach-Instantiierung bei Konstanten nicht weiter tragisch ist, muss ein Name eindeutig sein.

    all: main.exe
    
    clean:
            -rm main.exe libtest.so
    
    main.exe: main.c libtest.so
            gcc -Wall --pedantic -O3 -ldl $< -o $@
            strip $@
    
    libtest.so: lib.c
            gcc -Wall --pedantic -O3 --shared --optimize $< -o $@ -DUSE_STATIC
            strip $@
    
    test: all
            LD_LIBRARY_PATH=. ./main.exe
            nm main.exe
            nm libtest.so
    
    /* main.c */
    
    #include <stdio.h>
    #include <dlfcn.h>
    
    int main(void)
    {
        int * foo;
        char * err;
    
        void * so = dlopen("libtest.so", RTLD_NOW);
        if (!so)
        {
            fprintf(stderr, "%s\n", dlerror());
            return 1;
        }
    
        foo = dlsym(so, "foo");
        err = dlerror();
        if (err)
            fprintf(stderr, "%s\n", err);
        else
            printf("foo=%d\n", *foo);
        dlclose(so);
    
        return 0;
    }
    
    /* lib.c */
    
    #if __GNUC__ >= 4
      #define DLL_PUBLIC __attribute__ ((visibility("default")))
      #define DLL_LOCAL  __attribute__ ((visibility("hidden")))
    #else
      #define DLL_PUBLIC
      #define DLL_LOCAL static
    #endif
    
    #if USE_STATIC
      #define VISIBILITY DLL_LOCAL
    #else
      #define VISIBILITY DLL_PUBLIC
    #endif
    
    VISIBILITY int const foo = 42;
    

Anmelden zum Antworten