Die Frage war einfach c Funktionen nicht c ++ static
Methoden, wie in Kommentaren erläutert.
Ich verstehe, was eine static
Variable ist, aber was ist eine static
Funktion?
Und warum ist es so, dass, wenn ich eine Funktion deklariere, sagen void print_matrix
wir, sagen wir a.c
(OHNE a.h
) und einschließen "a.c"
- ich verstehe "print_matrix@@....) already defined in a.obj"
, ABER wenn ich sie deklariere static void print_matrix
, kompiliert sie dann?
UPDATE Nur um die Dinge zu klären - ich weiß, dass das Einschließen .c
schlecht ist, wie viele von Ihnen betonten. Ich mache es nur, um vorübergehend Speicherplatz freizugeben, main.c
bis ich eine bessere Vorstellung davon habe, wie all diese Funktionen in Eigen- .h
und .c
Dateien gruppiert werden können. Nur eine vorübergehende, schnelle Lösung.
quelle
Es gibt einen großen Unterschied zwischen statischen Funktionen in C und statischen Elementfunktionen in C ++. In C ist eine statische Funktion außerhalb ihrer Übersetzungseinheit, der Objektdatei, in die sie kompiliert wird, nicht sichtbar. Mit anderen Worten, wenn eine Funktion statisch gemacht wird, wird ihr Umfang eingeschränkt. Sie können sich eine statische Funktion als "privat" für ihre * .c-Datei vorstellen (obwohl dies nicht unbedingt korrekt ist).
In C ++ kann "statisch" auch für Elementfunktionen und Datenelemente von Klassen gelten. Ein statisches Datenelement wird auch als "Klassenvariable" bezeichnet, während ein nicht statisches Datenelement eine "Instanzvariable" ist. Dies ist die Smalltalk-Terminologie. Dies bedeutet, dass nur eine Kopie eines statischen Datenelements von allen Objekten einer Klasse gemeinsam genutzt wird, während jedes Objekt über eine eigene Kopie eines nicht statischen Datenelements verfügt. Ein statisches Datenelement ist also im Wesentlichen eine globale Variable, dh ein Mitglied einer Klasse.
Nicht statische Elementfunktionen können auf alle Datenelemente der Klasse zugreifen: statisch und nicht statisch. Statische Elementfunktionen können nur für statische Datenelemente ausgeführt werden.
Eine Möglichkeit, darüber nachzudenken, besteht darin, dass in C ++ statische Datenelemente und statische Elementfunktionen nicht zu einem Objekt gehören, sondern zur gesamten Klasse.
quelle
Es gibt zwei Verwendungszwecke für das Schlüsselwort static, wenn es um Funktionen in C ++ geht.
Die erste besteht darin, die Funktion als intern verknüpft zu markieren, damit sie in anderen Übersetzungseinheiten nicht referenziert werden kann. Diese Verwendung ist in C ++ veraltet. Für diese Verwendung werden unbenannte Namespaces bevorzugt.
Die zweite Verwendung erfolgt im Kontext einer Klasse. Wenn eine Klasse eine statische Elementfunktion hat, bedeutet dies, dass die Funktion ein Mitglied der Klasse ist (und den üblichen Zugriff auf andere Mitglieder hat), aber nicht über ein bestimmtes Objekt aufgerufen werden muss. Mit anderen Worten, innerhalb dieser Funktion gibt es keinen "this" -Zeiger.
quelle
Beispiel für einen minimalen ausführbaren Bereich mit mehreren Dateien
Hier zeige ich, wie
static
sich der Umfang der Funktionsdefinitionen auf mehrere Dateien auswirkt.ac
Haupt c
GitHub stromaufwärts .
Kompilieren und ausführen:
Ausgabe:
Deutung
sf
, eine für jede Dateif
Wie üblich, je kleiner der Bereich, desto besser. Deklarieren
static
Sie daher immer Funktionen, wenn Sie können.In der C-Programmierung werden Dateien häufig verwendet, um "Klassen"
static
darzustellen , und Funktionen repräsentieren "private" Methoden der Klasse.Ein übliches C-Muster besteht darin, eine
this
Struktur als erstes "Methoden" -Argument weiterzugeben , was C ++ im Grunde genommen unter der Haube tut.Was Standards dazu sagen
C99 N1256 Entwurf 6.7.1 "Speicherklassenspezifizierer" besagt, dass dies
static
ein "Speicherklassenspezifizierer" ist.6.2.2 / 3 "Verknüpfungen von Kennungen"
static
impliziertinternal linkage
:und 6.2.2 / 2 sagt, dass
internal linkage
sich das wie in unserem Beispiel verhält:Dabei ist "Übersetzungseinheit" eine Quelldatei nach der Vorverarbeitung.
Wie implementiert GCC es für ELF (Linux)?
Mit der
STB_LOCAL
Bindung.Wenn wir kompilieren:
und zerlegen Sie die Symboltabelle mit:
Die Ausgabe enthält:
Die Bindung ist also der einzige signifikante Unterschied zwischen ihnen.
Value
ist nur ihr Versatz in den.bss
Abschnitt, also erwarten wir, dass es anders ist.STB_LOCAL
ist in der ELF-Spezifikation unter http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html dokumentiert :Das macht es zu einer perfekten Wahl für die Darstellung
static
.Funktionen ohne statische Aufladung sind
STB_GLOBAL
und die Spezifikation sagt:Dies stimmt mit den Verknüpfungsfehlern bei mehreren nicht statischen Definitionen überein.
Wenn wir die Optimierung mit ankurbeln
-O3
, wird dassf
Symbol vollständig aus der Symboltabelle entfernt: Es kann sowieso nicht von außen verwendet werden. TODO warum statische Funktionen überhaupt in der Symboltabelle behalten, wenn keine Optimierung erfolgt? Können sie für irgendetwas verwendet werden?Siehe auch
extern
ist das Gegenteil vonstatic
und Funktionen sind bereitsextern
standardmäßig: Wie verwende ich extern, um Variablen zwischen Quelldateien zu teilen?Anonyme C ++ - Namespaces
In C ++ möchten Sie möglicherweise anonyme Namespaces anstelle von statischen verwenden, wodurch ein ähnlicher Effekt erzielt wird. Die Typdefinitionen werden jedoch weiter ausgeblendet: Unbenannte / anonyme Namespaces im Vergleich zu statischen Funktionen
quelle
void f() { puts("sf"); }
(dh zwei Definitionen vonf()
) verursacht undefiniertes Verhalten, ohne dass eine Diagnose erforderlich ist. Es ist ein Problem mit der Qualität des Linkers, wenn tatsächlich eine Fehlermeldung angezeigt wird.Im Folgenden geht es um einfache C-Funktionen. In einer C ++ - Klasse hat der Modifikator 'static' eine andere Bedeutung.
Wenn Sie nur eine Datei haben, macht dieser Modifikator absolut keinen Unterschied. Der Unterschied besteht in größeren Projekten mit mehreren Dateien:
In C wird jedes "Modul" (eine Kombination aus sample.c und sample.h) unabhängig kompiliert und anschließend wird jede dieser kompilierten Objektdateien (sample.o) vom Linker mit einer ausführbaren Datei verknüpft.
Angenommen, Sie haben mehrere Dateien, die Sie in Ihre Hauptdatei aufnehmen, und zwei davon haben eine Funktion, die nur intern verwendet wird.
add(int a, b)
Der Compiler würde leicht Objektdateien für diese beiden Module erstellen, aber der Linker gibt einen Fehler aus, weil Es findet zwei Funktionen mit demselben Namen und weiß nicht, welche es verwenden soll (auch wenn nichts zu verknüpfen ist, da sie nicht an einer anderen Stelle als in einer eigenen Datei verwendet werden).Aus diesem Grund machen Sie diese Funktion, die nur intern verwendet wird, zu einer statischen Funktion. In diesem Fall erstellt der Compiler nicht das typische Flag "Sie können dieses Ding verknüpfen" für den Linker, sodass der Linker diese Funktion nicht sieht und keinen Fehler generiert.
quelle
Erstens: Es ist im Allgemeinen eine schlechte Idee, eine
.cpp
Datei in eine andere Datei aufzunehmen - dies führt zu folgenden Problemen :-) Der normale Weg besteht darin, separate Kompilierungseinheiten zu erstellen und eine Header-Datei für die enthaltene Datei hinzuzufügen.Zweitens:
C ++ hat hier eine verwirrende Terminologie - ich wusste nichts davon, bis in Kommentaren darauf hingewiesen wurde.
a)
static functions
- von C geerbt und wovon Sie hier sprechen. Außerhalb jeder Klasse. Eine statische Funktion bedeutet, dass sie außerhalb der aktuellen Kompilierungseinheit nicht sichtbar ist. In Ihrem Fall verfügt a.obj also über eine Kopie und Ihr anderer Code über eine unabhängige Kopie. (Aufblähen der endgültigen ausführbaren Datei mit mehreren Kopien des Codes).b)
static member function
- was für Objektorientierung Begriffe eine statische Methode . Lebt in einer Klasse. Sie rufen dies mit der Klasse und nicht über eine Objektinstanz auf.Diese beiden unterschiedlichen statischen Funktionsdefinitionen sind völlig unterschiedlich. Sei vorsichtig - hier sind Drachen.
quelle
Statische Funktionsdefinitionen markieren dieses Symbol als intern. Es ist also nicht für Links von außen sichtbar, sondern nur für Funktionen in derselben Kompilierungseinheit, normalerweise in derselben Datei.
quelle
Eine statische Funktion kann im Gegensatz zu einer Instanz der Klasse für die Klasse selbst aufgerufen werden.
Zum Beispiel wäre eine nicht statische:
Diese Methode funktioniert für eine Instanz der Klasse, nicht für die Klasse selbst. Sie können jedoch eine statische Methode verwenden, die ohne Instanz funktioniert. Dies wird manchmal im Factory-Muster verwendet:
quelle
Minor nit: Statische Funktionen sind für eine Übersetzungseinheit sichtbar. In den meisten praktischen Fällen handelt es sich dabei um die Datei, in der die Funktion definiert ist. Der Fehler, den Sie erhalten, wird häufig als Verstoß gegen die One Definition Rule bezeichnet.
Der Standard sagt wahrscheinlich etwas wie:
Das ist die C-Sichtweise auf statische Funktionen. Dies ist in C ++ jedoch veraltet.
In C ++ können Sie außerdem Elementfunktionen als statisch deklarieren. Dies sind meistens Metafunktionen, dh sie beschreiben / modifizieren nicht das Verhalten / den Zustand eines bestimmten Objekts, sondern wirken auf die gesamte Klasse selbst. Dies bedeutet auch, dass Sie kein Objekt erstellen müssen, um eine statische Elementfunktion aufzurufen. Dies bedeutet auch, dass Sie nur innerhalb einer solchen Funktion Zugriff auf statische Elementvariablen erhalten.
Ich würde zu Parrots Beispiel das Singleton-Muster hinzufügen, das auf dieser Art einer statischen Elementfunktion basiert, um ein einzelnes Objekt während der gesamten Lebensdauer eines Programms abzurufen / zu verwenden.
quelle
Die Antwort auf die statische Funktion hängt von der Sprache ab:
1) In Sprachen ohne OOPS wie C bedeutet dies, dass auf die Funktion nur innerhalb der Datei zugegriffen werden kann, in der sie definiert ist.
2) In Sprachen mit OOPS wie C ++ bedeutet dies, dass die Funktion direkt in der Klasse aufgerufen werden kann, ohne eine Instanz davon zu erstellen.
quelle
static
einen Dateibereich, wie in C.Da statische Funktion nur in dieser Datei sichtbar ist. Tatsächlich kann der Compiler einige Optimierungen für Sie vornehmen , wenn Sie für eine Funktion "statisch" deklarieren.
Hier ist ein einfaches Beispiel.
Haupt c
Und kompilieren mit
Sie werden sehen, dass es fehlgeschlagen ist. Weil Sie sogar die Ghost () - Funktion nicht implementieren.
Aber was ist, wenn wir den folgenden Befehl verwenden?
Es ist erfolgreich , und dieses Programm kann normal ausgeführt werden.
Warum? Es gibt 3 wichtige Punkte.
Nur wenn diese drei Bedingungen erfüllt sind, können Sie die Kompilierung bestehen. Aufgrund dieser "statischen" Deklaration kann der Compiler bestätigen, dass test () NIEMALS in einer anderen Datei aufgerufen wird. Ihr Compiler kann test () beim Kompilieren entfernen. Da wir test () nicht benötigen, spielt es keine Rolle, ob ghost () definiert oder implementiert ist.
quelle
Beginnen wir am Anfang.
Es basiert alles auf einer Sache namens "Verknüpfung":
Wenn eine Funktion ohne Speicherklassenspezifizierer definiert ist, verfügt die Funktion
extern
standardmäßig über eine Verknüpfung:Das bedeutet, dass - wenn Ihr Programm aus mehreren Übersetzungseinheiten / Quelldateien (
.c
oder.cpp
) besteht - die Funktion in allen Übersetzungseinheiten / Quelldateien Ihres Programms sichtbar ist.Dies kann in einigen Fällen ein Problem sein. Was ist, wenn Sie z. B. zwei verschiedene Funktionen (Definitionen) verwenden möchten, jedoch mit demselben Funktionsnamen in zwei verschiedenen Kontexten (eigentlich dem Dateikontext).
In C und C ++ hilft jetzt das
static
Qualifikationsmerkmal für die Speicherklasse , das auf eine Funktion im Dateibereich angewendet wird (keine statische Elementfunktion einer Klasse in C ++ oder eine Funktion in einem anderen Block), und zeigt an, dass die jeweilige Funktion nur innerhalb von sichtbar ist die Übersetzungseinheit / Quelldatei, in der sie definiert wurde, und nicht in den anderen TLUs / Dateien.Eine
static
Funktion ist also nur dann sinnvoll, wenn:Ihr Programm besteht aus mehreren Übersetzungseinheiten / Quelldateien (
.c
oder.cpp
).und
Sie möchten den Umfang einer Funktion auf die Datei beschränken, in der die spezifische Funktion definiert ist.
Wenn nicht beide Anforderungen übereinstimmen, müssen Sie sich nicht darum kümmern, eine Funktion als zu qualifizieren
static
.Randnotizen:
Wie bereits erwähnt, hat eine
static
Funktion überhaupt keinen Unterschied zwischen C und C ++, da dies eine von C geerbte Funktion C ++ ist.Es spielt keine Rolle, dass es in der C ++ - Community eine herzzerreißende Debatte über die Abwertung qualifizierender Funktionen
static
im Vergleich zur Verwendung unbenannter Namespaces gibt , die zuerst durch einen falsch platzierten Absatz im C ++ 03-Standard initialisiert wurde und die Verwendung von deklariert statische Funktionen als veraltet, die bald vom Komitee selbst überarbeitet und in C ++ 11 entfernt wurden.Dies war Gegenstand verschiedener SO-Fragen:
Unbenannte / anonyme Namespaces vs. statische Funktionen
Überlegenheit des unbenannten Namespace gegenüber dem statischen?
Warum ist ein unbenannter Namespace eine "überlegene" Alternative zu statischen?
Verfall des statischen Schlüsselworts ... nicht mehr?
Tatsächlich ist es gemäß C ++ - Standard noch nicht veraltet. Somit ist die Verwendung von
static
Funktionen immer noch legitim. Selbst wenn unbenannte Namespaces Vorteile haben, unterliegt die Diskussion über die Verwendung oder Nichtverwendung statischer Funktionen in C ++ dem eigenen Verstand (meinungsbasiert) und ist daher für diese Website nicht geeignet.quelle