Stilfrage: Globale Konstanten



  • 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