Redeklaration, aber Meldung fehlt



  • Hallo,

    wenn man eine Variable wiederholt deklariert, gibt der Compiler (bei mir gcc 4.6.1) doch sonst schonmal sowas wie:

    Fehler: "Redeklaration von »variable« ohne Bindung" bzw. englisch: "redeclaration of ... with no linkage" aus. Dahinter freundlicherweise auch noch die Zeilen- u. Spaltennummer der bereits gemachten Deklaration mit der Anmerkung: "Vorherige Deklaration von »variable« war hier" bzw. "previous declaration of ... was here".

    Beim erfolgreichen (!) Kompilieren von Folgendem (mit doppelter Deklaration der Variable b in den Zeilen 6 und 12) kommt jedoch gar keine Meldung:

    // Programm: mit_int.c
    #include <stdio.h>
    main()
    {
        int feld[5];
        int b; for(b=0; b<5; b++) feld[b]=b+7;
        printf ("feld[..] wurde initialisiert.\n\n");
    
        int a=0;
        while(a<3)
        {
            int b=0; // ja, b wurde nutzlos auf Null gesetzt.
            printf ("Das %i. Feldelement ist %i.\n\n",a,feld[a]);
            a++;
        }
    }
    

    Ich hoffe, mein beabsichtigtes Minimalbeispiel möglichst weit minimiert zu haben (Ich wusste nicht, welche zur Fragestellung überflüssigen Teile ich sonst noch hätte rausschneiden können). Das aus Obigem mit dem Compiler erzeugte Programm mit dem wiederholten int b ist übrigens um 1 Byte kleiner, als das, was entsteht, wenn man aus Zeile 12 das int weglässt:

    // Programm: ohne_int.c
    #include <stdio.h>
    main()
    {
        int feld[5];
        int b; for(b=0; b<5; b++) feld[b]=b+7;
        printf ("feld[..] wurde initialisiert.\n\n");
    
        int a=0;
        while(a<3)
        {
            b=0; // ja, b wurde nutzlos auf Null gesetzt.
            printf ("Das %i. Feldelement ist %i.\n\n",a,feld[a]);
            a++;
        }
    }
    

    Die Ausgaben beider Programme stimmen exakt überein. Was mach ich denn da eigentlich anders, wenn ich das b erneut deklariere und warum schweigt der Compiler dazu?


  • Mod

    Gültigkeitsbereiche. Englisch: Scope.



  • Dunkelziffer schrieb:

    Das aus Obigem mit dem Compiler erzeugte Programm mit dem wiederholten int b ist übrigens um 1 Byte kleiner, als das, was entsteht, wenn man aus Zeile 12 das int weglässt

    Bei welcher Optimierung?

    Da du b in der while-Schleife gar nicht nutzt, lässt es der Compiler bei eingeschalteter Optimierung auch weg.



  • SeppJ schrieb:

    Gültigkeitsbereiche.

    Danke, SeppJ. Also habe ich "8.2 Sichtbarkeit von Variablen" im Buch von H. Erlenkötter nicht beachtet.

    Englisch: Scope.

    Vielen Dank euch beiden!

    DirkB schrieb:

    Dunkelziffer schrieb:

    Programm mit dem wiederholten int b ist übrigens um 1 Byte kleiner, als das, wenn man aus Zeile 12 das int weglässt

    Bei welcher Optimierung?

    Vom Einschalten einer Optimierung beim Compiler habe ich keinen Schimmer.
    Alles, was ich mit Hilfe von GNU Make 3.81 dem Compiler gegeben habe, ist:

    $ make ohne_int # und danach erscheint da:
    cc     ohne_int.c   -o ohne_int
    

    und die ausführbare Datei ohne_int ist entstanden.

    Da du b in der while-Schleife gar nicht nutzt, lässt es der Compiler bei eingeschalteter Optimierung auch weg.

    Okay, dann wird mir das klar. Passiert anscheinend auch ohne eine von mir veranlasste Optimierung:
    Bei "ohne_int.c" wird das nur einmal deklarierte b vom äußeren compound statement (der Block {}, der zu main gehört) in dem inneren compound statement {} (das zu while gehört) durch die Anweisung b=0 verändert (vor der Veränderung hatte es den Wert 4) und es gibt nur einen einzigen scope für b.

    Wohingegen es bei "mit_int.c" innerhalb des compound statement vom while einen eigenen scope hat und bei Rückkehr des Programmschrittes in das äußere compound statement wieder vom b des "alten" scope überschrieben wird.



  • Dunkelziffer schrieb:

    Vom Einschalten einer Optimierung beim Compiler habe ich keinen Schimmer.
    Alles, was ich mit Hilfe von GNU Make 3.81 dem Compiler gegeben habe, ist:

    $ make ohne_int # und danach erscheint da:
    cc     ohne_int.c   -o ohne_int
    

    und die ausführbare Datei ohne_int ist entstanden.

    Dann spendier dem Verzeichnis noch ein minimales Makefile (das Du auch genauso nennst: Makefile):

    # Makefile
    # alle (-W)arnungen und ein pedantischer Compiler
    CPPFLAGS=-Wall -pedantic
    # C nach dem Standard von 2011
    CFLAGS=-std=c11
    


  • Das geht bei mir nicht.

    $ cat Makefile 
    # Makefile
    # alle (-W)arnungen und ein pedantischer Compiler
    CPPFLAGS=-Wall -pedantic
    # C nach dem Standard von 2011
    CFLAGS=-std=c11
    $ make ohne_int
    cc -std=c11 -Wall -pedantic   ohne_int.c   -o ohne_int
    cc1: Fehler: nicht erkannte Kommandozeilenoption »-std=c11«
    make: *** [ohne_int] Fehler 1
    $
    

    Mit, wie schon geschrieben, gcc 4.6.1 und GNU Make 3.81.

    An gcc 5.3.0 und GNU Make 4.1 werde ich nicht so leicht heran kommen können, aber erstmal kann ich alles noch unter einem anderen Debian ausprobieren, vielleicht heute abend noch.



  • Dunkelziffer schrieb:

    Das geht bei mir nicht.

    $ cat Makefile 
    # Makefile
    # alle (-W)arnungen und ein pedantischer Compiler
    CPPFLAGS=-Wall -pedantic
    # C nach dem Standard von 2011
    CFLAGS=-std=c11
    $ make ohne_int
    cc -std=c11 -Wall -pedantic   ohne_int.c   -o ohne_int
    cc1: Fehler: nicht erkannte Kommandozeilenoption »-std=c11«
    make: *** [ohne_int] Fehler 1
    $
    

    Mit, wie schon geschrieben, gcc 4.6.1 und GNU Make 3.81.

    An gcc 5.3.0 und GNU Make 4.1 werde ich nicht so leicht heran kommen können, aber erstmal kann ich alles noch unter einem anderen Debian ausprobieren, vielleicht heute abend noch.

    Versuch c99 statt c11 , oder lass die CFLAGS= Zeile weg. Das sollte dann tun.


Log in to reply