Beispiel für den Geltungsbereich von Mehrdateivariablen
Hier wird veranschaulicht, wie sich static auf den Geltungsbereich von Funktionsdefinitionen über mehrere Dateien hinweg auswirkt.
a.c
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://stackoverflow.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*int i = 0;*/
/* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */
/*int i;*/
/* OK: extern. Will use the one in main. */
extern int i;
/* OK: only visible to this file. */
static int si = 0;
void a() {
i++;
si++;
puts("a()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
main.c
#include <stdio.h>
int i = 0;
static int si = 0;
void a();
void m() {
i++;
si++;
puts("m()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
int main() {
m();
m();
a();
a();
return 0;
}
GitHub vorgelagert .
Kompilieren und ausführen:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Ausgabe:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
Auslegung
- gibt es zwei getrennte Variablen für
si
eine für jede Datei
- gibt es eine einzige gemeinsame Variable für
i
Wie üblich gilt: Je kleiner der Anwendungsbereich, desto besser, also immer Variablen deklarieren static
wenn Sie können.
In der C-Programmierung werden häufig Dateien zur Darstellung von "Klassen" verwendet, und static
Variablen stellen private statische Mitglieder der Klasse dar.
Was die Normen dazu sagen
C99 N1256 Entwurf 6.7.1 "Speicherklassenspezifizierer" besagt, dass static
ist ein "Speicherklassenbezeichner".
6.2.2/3 "Verknüpfungen von Identifikatoren" sagt static
impliziert internal linkage
:
Wenn die Deklaration eines Dateibereichskennzeichens für ein Objekt oder eine Funktion den Speicherklassenspezifizierer static enthält, hat das Kennzeichen eine interne Verknüpfung.
und 6.2.2/2 besagt, dass internal linkage
verhält sich wie in unserem Beispiel:
In der Menge der Übersetzungseinheiten und Bibliotheken, die ein ganzes Programm bilden, bezeichnet jede Deklaration eines bestimmten Bezeichners mit externer Verknüpfung dasselbe Objekt oder dieselbe Funktion. Innerhalb einer Übersetzungseinheit bezeichnet jede Deklaration eines Bezeichners mit interner Verknüpfung dasselbe Objekt oder dieselbe Funktion.
wobei "Übersetzungseinheit" eine Quelldatei nach der Vorverarbeitung ist.
Wie implementiert GCC es für ELF (Linux)?
Mit dem STB_LOCAL
Bindung.
Wenn wir kompilieren:
int i = 0;
static int si = 0;
und demontieren Sie die Symboltabelle mit:
readelf -s main.o
die Ausgabe enthält:
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i
Die Bindung ist also der einzige wesentliche Unterschied zwischen ihnen. Value
ist nur ihr Offset in der .bss
Abschnitt, so dass wir davon ausgehen, dass er sich unterscheiden wird.
STB_LOCAL
ist in der ELF-Spezifikation dokumentiert unter http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL Lokale Symbole sind außerhalb der Objektdatei, die ihre Definition enthält, nicht sichtbar. Lokale Symbole desselben Namens können in mehreren Dateien existieren, ohne sich gegenseitig zu behindern
was sie zu einer perfekten Wahl für die Darstellung von static
.
Variablen ohne Statik sind STB_GLOBAL
und in der Spezifikation steht:
Wenn der Link-Editor mehrere verschiebbare Objektdateien kombiniert, lässt er keine Mehrfachdefinitionen von STB_GLOBAL-Symbolen mit demselben Namen zu.
was mit den Verknüpfungsfehlern bei mehreren nicht statischen Definitionen kohärent ist.
Wenn wir die Optimierung mit -O3
die si
Symbol wird komplett aus der Symboltabelle entfernt: es kann von außen sowieso nicht verwendet werden. TODO Warum sollten statische Variablen überhaupt in der Symboltabelle verbleiben, wenn es keine Optimierung gibt? Können sie für irgendetwas verwendet werden? Vielleicht für die Fehlersuche.
Siehe auch
C++ anonyme Namespaces
In C++ können Sie anonyme Namespaces anstelle von statischen Namespaces verwenden, wodurch ein ähnlicher Effekt erzielt wird, die Typdefinitionen aber noch weiter versteckt werden: Unbenannte/anonyme Namensräume vs. statische Funktionen
9 Stimmen
Verwandt: Statisch (Stichwort) @ Wikipedia
42 Stimmen
Welchen Grund gibt es, "in einem C-Programm" am Ende des Titels zu entfernen, @Lundin? Es ist leicht redundant in der Gegenwart von Tag c aber es ermöglicht mir, die Kategorisierung schneller zu sehen, ohne die Tags zu inspizieren. Diese Redundanz ist sehr angenehm, wenn ich die Frage aus einer Richtung erhalte, die auch Fragen zu anderen Sprachen enthalten kann, z. B. statisch oder Google-Suche.
7 Stimmen
@Lundin Ich ziehe es vor, das "C" im Titel zu behalten, da SO nur ein Tag an den Titel anhängt (das häufigste?). Was ist, wenn eines Tages "Syntax" mehr Fragen als C erreicht (da es eine sprachenübergreifende Sache ist)? Ich würde lieber das explizite Verhalten verwenden :-) Edit: ah aber es gibt eine Meta-Frage, die etwas anderes sagt: meta.stackexchange.com/questions/19190/
3 Stimmen
Diese Erklärung habe ich auf Quora gefunden. Unbedingt lesenswert!
1 Stimmen
Die Speicherdauer von static ist bis zum Ende des Programms und nicht bis zum Ende des Bereichs.
0 Stimmen
Verwandt: Was ist eine "statische" Funktion in C?