Das Schlüsselwort 'statisch' in C hat zwei grundlegend unterschiedliche Bedeutungen.
Umfang einschränken
In diesem Zusammenhang wird 'static' mit 'extern' gepaart, um den Umfang einer Variablen oder eines Funktionsnamens zu steuern. Statisch bewirkt, dass der Name der Variablen oder Funktion nur innerhalb einer einzelnen Kompilierungseinheit und nur für Code verfügbar ist, der nach der Deklaration / Definition im Text der Kompilierungseinheit vorhanden ist.
Diese Einschränkung selbst bedeutet nur dann etwas, wenn Sie mehr als eine Kompilierungseinheit in Ihrem Projekt haben. Wenn Sie nur eine Kompilierungseinheit haben, macht sie immer noch Dinge, aber diese Effekte sind meistens sinnlos (es sei denn, Sie möchten in Objektdateien graben, um zu lesen, was der Compiler generiert hat.)
Wie bereits erwähnt, wird dieses Schlüsselwort in diesem Kontext mit dem Schlüsselwort 'extern' gepaart, was das Gegenteil bewirkt - indem der Name der Variablen oder Funktion mit demselben Namen verknüpft wird, der in anderen Kompilierungseinheiten gefunden wird. Sie können also "statisch" so betrachten, dass die Variable oder der Name in der aktuellen Kompilierungseinheit gefunden werden muss, während "extern" die Verknüpfung zwischen Kompilierungseinheiten zulässt.
Statische Lebensdauer
Statische Lebensdauer bedeutet, dass die Variable während der gesamten Dauer des Programms vorhanden ist (wie lange das auch sein mag). Wenn Sie eine Variable innerhalb einer Funktion mit 'statisch' deklarieren / definieren, bedeutet dies, dass die Variable irgendwann vor ihrer ersten Verwendung erstellt wird ( Dies bedeutet, dass jedes Mal, wenn ich es erlebt habe, die Variable vor dem Start von main () erstellt und danach nicht zerstört wird. Nicht einmal, wenn die Ausführung der Funktion abgeschlossen ist und sie zu ihrem Aufrufer zurückkehrt. Und genau wie statische Lebensdauervariablen, die außerhalb von Funktionen deklariert wurden, werden sie im selben Moment - bevor main () startet - auf eine semantische Null (wenn keine Initialisierung angegeben ist) oder auf einen bestimmten expliziten Wert (falls angegeben) initialisiert.
Dies unterscheidet sich von Funktionsvariablen vom Typ 'auto', die bei jeder Eingabe der Funktion neu erstellt werden (oder als ob sie neu wären) und dann beim Beenden der Funktion zerstört werden (oder als ob sie zerstört würden).
Im Gegensatz zu den Auswirkungen der Anwendung von "statisch" auf eine Variablendefinition außerhalb einer Funktion, die sich direkt auf ihren Gültigkeitsbereich auswirkt, hat die Deklaration einer Funktionsvariablen (offensichtlich innerhalb eines Funktionskörpers) als "statisch" keine Auswirkungen auf ihren Gültigkeitsbereich. Der Umfang wird dadurch bestimmt, dass er innerhalb eines Funktionskörpers definiert wurde. In Funktionen definierte statische Lebensdauervariablen haben denselben Gültigkeitsbereich wie andere in Funktionskörpern definierte 'Auto'-Variablen - Funktionsumfang.
Zusammenfassung
Das Schlüsselwort "statisch" hat also unterschiedliche Kontexte mit "sehr unterschiedlichen Bedeutungen". Der Grund, warum es auf zwei Arten verwendet wurde, war, die Verwendung eines anderen Schlüsselworts zu vermeiden. (Es gab eine lange Diskussion darüber.) Es wurde die Ansicht vertreten, dass Programmierer die Verwendung tolerieren könnten, und der Wert, ein weiteres Schlüsselwort in der Sprache zu vermeiden, war wichtiger (als ansonsten Argumente).
(Alle außerhalb von Funktionen deklarierten Variablen haben eine statische Lebensdauer und benötigen nicht das Schlüsselwort 'static', um dies zu erfüllen. Auf diese Weise wurde das dort zu verwendende Schlüsselwort freigegeben, um etwas völlig anderes zu bedeuten: 'nur in einer einzigen Kompilierung sichtbar Einheit. 'Es ist eine Art Hack.)
Besonderer Hinweis
statisches flüchtiges vorzeichenloses Zeichen PORTB @ 0x06;
Das Wort "statisch" sollte hier so interpretiert werden, dass der Linker nicht versucht, mehrere Vorkommen von PORTB abzugleichen , die in mehr als einer Kompilierungseinheit gefunden werden können (vorausgesetzt, Ihr Code hat mehr als eine).
Es verwendet eine spezielle (nicht portierbare) Syntax, um den "Speicherort" (oder den numerischen Wert des Etiketts, der normalerweise eine Adresse ist) von PORTB anzugeben. Der Linker erhält also die Adresse und muss keine dafür finden. Wenn Sie zwei Kompilierungseinheiten hätten, die diese Zeile verwenden, würden sie ohnehin jeweils auf dieselbe Stelle zeigen. Hier muss es also nicht als "extern" bezeichnet werden.
Hätten sie "extern" verwendet, könnte dies ein Problem darstellen. Der Linker könnte dann mehrere Verweise auf PORTB sehen (und versuchen, sie abzugleichen), die in mehreren Zusammenstellungen gefunden wurden. Wenn alle eine Adresse wie diese angeben und die Adressen aus irgendeinem Grund NICHT gleich sind [Fehler?], Was soll sie dann tun? Beschweren? Oder? (Technisch gesehen würde bei 'extern' die Faustregel lauten, dass nur EINE Kompilierungseinheit den Wert angeben würde und die anderen nicht.)
Es ist einfach einfacher, es als "statisch" zu kennzeichnen, um zu vermeiden, dass sich der Linker über Konflikte Sorgen macht, und einfach die Schuld für Fehler bei nicht übereinstimmenden Adressen zu geben, wenn jemand die Adresse in etwas geändert hat, das es nicht sein sollte.
In beiden Fällen wird die Variable als "statische Lebensdauer" behandelt. (Und "flüchtig".)
Eine Deklaration ist keine Definition , aber alle Definitionen sind Deklarationen
In C erstellt eine Definition ein Objekt. Es erklärt es auch. Eine Deklaration erstellt jedoch normalerweise kein Objekt (siehe Aufzählungszeichen unten).
Das Folgende sind Definitionen und Erklärungen:
static int a;
static int a = 7;
extern int b = 5;
extern int f() { return 10; }
Das Folgende sind keine Definitionen, sondern nur Erklärungen:
extern int b;
extern int f();
Beachten Sie, dass die Deklarationen kein tatsächliches Objekt erstellen. Sie deklarieren nur die Details dazu, die der Compiler dann verwenden kann, um korrekten Code zu generieren und gegebenenfalls Warn- und Fehlermeldungen bereitzustellen.
Oben sage ich "normalerweise" mit Rat und Tat. In einigen Fällen kann eine Deklaration ein Objekt erstellen und wird daher vom Linker (niemals vom Compiler) zu einer Definition heraufgestuft. Selbst in diesem seltenen Fall glaubt der C-Compiler, dass die Deklaration nur eine Deklaration ist. Es ist die Linker-Phase, die alle notwendigen Werbeaktionen für eine Erklärung vornimmt. Denken Sie sorgfältig daran.
Sollte sich in den obigen Beispielen herausstellen, gibt es nur Deklarationen für ein "extern int b"; In allen verknüpften Kompilierungseinheiten trägt der Linker die Verantwortung für die Erstellung einer Definition. Beachten Sie, dass dies ein Ereignis zur Verbindungszeit ist. Der Compiler ist sich während der Kompilierung überhaupt nicht bewusst. Es kann nur zum Zeitpunkt der Verknüpfung festgestellt werden, ob eine Deklaration dieses Typs am meisten beworben wird.
Dem Compiler ist bekannt, dass "static int a;" kann vom Linker zur Linkzeit nicht hochgestuft werden, daher ist dies tatsächlich eine Definition zur Kompilierungszeit .