Was bringt es, eine Funktion in C statisch zu machen?
statische Funktion in C
Cenoc
pmg
Funktion machen static
verbirgt es vor anderen Übersetzungseinheiten, was zur Bereitstellung beiträgt Verkapselung.
helper_file.c
int f1(int); /* prototype */
static int f2(int); /* prototype */
int f1(int foo) {
return f2(foo); /* ok, f2 is in the same translation unit */
/* (basically same .c file) as f1 */
}
int f2(int foo) {
return 42 + foo;
}
Haupt c:
int f1(int); /* prototype */
int f2(int); /* prototype */
int main(void) {
f1(10); /* ok, f1 is visible to the linker */
f2(12); /* nope, f2 is not visible to the linker */
return 0;
}
-
Ist die Übersetzungseinheit hier die richtige Terminologie? Wäre die Objektdatei nicht genauer? Soweit ich weiß, ist eine statische Funktion vor dem Linker verborgen und der Linker arbeitet nicht mit Übersetzungseinheiten.
– Steven Eckhoff
13. Februar 2014 um 18:32 Uhr
-
Ich hätte auch sagen sollen, dass ich es mir gerne so vorstelle, dass es vor dem Linker verborgen ist; es scheint so klarer.
– Steven Eckhoff
13. Februar 2014 um 18:51 Uhr
-
Also, interne Funktion (die wir sicher nicht außerhalb ihrer c-Datei aufrufen), sollten wir sie als statische Funktion setzen, richtig? Wir können also sicher sein, dass es nicht woanders anrufen kann. Vielen Dank 🙂
– Hqt
6. Juli 2014 um 3:30 Uhr
-
Wie kompiliert man das? Benutzt du
#include <helper_file.c>
? Ich denke, das würde es dann zu einer einzigen Übersetzungseinheit machen …– Kalt
23. August 2016 um 1:30 Uhr
-
@Atcold: So wie ich den Code geschrieben habe, fügen Sie einfach die 2 Quelldateien wie folgt in die Befehlszeile ein
gcc -std=c99 -pedantic -Wall -Wextra main.c helper_file.c
. Die Prototypen für die Funktionen sind in beiden Quelldateien vorhanden (keine Notwendigkeit für Header-Dateien). Der Linker löst die Funktionen auf.– pmg
23. August 2016 um 8:37 Uhr
Stefan Kanon
pmg ist genau richtig in Bezug auf die Kapselung; über das Verstecken der Funktion vor anderen Übersetzungseinheiten hinaus (oder besser gesagt, Weil davon), Funktionen machen static
kann auch bei Vorhandensein von Compileroptimierungen Leistungsvorteile bringen.
Weil ein static
Die Funktion kann nicht von irgendwo außerhalb der aktuellen Übersetzungseinheit aufgerufen werden (es sei denn, der Code nimmt einen Zeiger auf seine Adresse), der Compiler steuert alle Aufrufpunkte darin.
Dies bedeutet, dass es frei ist, eine nicht standardmäßige ABI zu verwenden, sie vollständig zu inlinen oder eine beliebige Anzahl anderer Optimierungen durchzuführen, die für eine Funktion mit externer Verknüpfung möglicherweise nicht möglich sind.
-
…es sei denn, die Adresse der Funktion ist belegt.
– Café
16. März 2011 um 0:06 Uhr
-
@caf Was meinst du damit, dass die Adresse der Funktion übernommen wird? Für mich ist die Vorstellung, dass Funktionen/Variablen Adressen haben oder zur Kompilierzeit Adressen zugewiesen werden, etwas verwirrend. Können Sie das bitte näher erläutern?
– SayeedHussain
2. August 2013 um 12:43 Uhr
-
@crypticcoder: Ihr Programm wird in den Speicher geladen, daher haben Funktionen auch einen Speicherort und die Adresse kann abgerufen werden. Mit einem Funktionszeiger könnten Sie jede davon aufrufen. Wenn Sie dies tun, wird die Liste der Optimierungen, die der Compiler durchführen kann, reduziert, da der Code an derselben Stelle intakt bleiben muss.
– Benutzer1454661
2. August 2013 um 17:23 Uhr
-
@crypticcoder: Ich meine, dass ein Ausdruck einen Zeiger auf die Funktion auswertet und etwas anderes damit macht, als die Funktion sofort aufzurufen. Wenn ein Zeiger auf a
static
Funktion die aktuelle Übersetzungseinheit maskiert, dann könnte diese Funktion direkt von anderen Übersetzungseinheiten aufgerufen werden.– Café
3. August 2013 um 0:02 Uhr
-
@caf Wenn die Adresse der Funktion verwendet wird, würde der Compiler dies erkennen und die in dieser Antwort erwähnten statischen Funktionsoptimierungen deaktivieren (z. B. unter Verwendung einer nicht standardmäßigen ABI)? Ich schätze, es müsste.
– Sevko
12. Juli 2018 um 15:52 Uhr
Das static
Schlüsselwort in C wird in einer kompilierten Datei (.c im Gegensatz zu .h) verwendet, sodass die Funktion nur in dieser Datei existiert.
Wenn Sie eine Funktion erstellen, generiert der Compiler normalerweise Cruft, die der Linker verwenden kann, um einen Funktionsaufruf mit dieser Funktion zu verknüpfen. Wenn Sie das Schlüsselwort static verwenden, können andere Funktionen innerhalb derselben Datei diese Funktion aufrufen (weil dies ohne Rückgriff auf den Linker möglich ist), während der Linker keine Informationen hat, die anderen Dateien den Zugriff auf die Funktion ermöglichen.
-
3Doub: Die Verwendung des Wortes „Cruft“ ist präziser, als Sie glauben. Im Zusammenhang mit der Frage ist “Cruft” das richtige Wort, das hier verwendet werden sollte.
– Erik Aronesty
20. November 2014 um 21:16 Uhr
-
@3Dublonen Ich stimme zu, dass es vereinfacht ist, aber ich denke, das macht es für Anfänger viel einfacher zu verstehen.
– Ingo Bürk
25. März 2015 um 7:47 Uhr
Quecksilber0114
Wenn ich mir die obigen Beiträge ansehe, möchte ich eine klarere Antwort geben:
Angenommen, unsere main.c
Datei sieht so aus:
#include "header.h"
int main(void) {
FunctionInHeader();
}
Betrachten Sie nun drei Fälle:
-
Fall 1: Unsere
header.h
Datei sieht so aus:#include <stdio.h> static void FunctionInHeader(); void FunctionInHeader() { printf("Calling function inside header\n"); }
Dann der folgende Befehl unter Linux:
gcc main.c -o main
wird gelingen! Das liegt daran, dass nach dem
main.c
Datei enthält dieheader.h
die Definition der statischen Funktion ist gleichmain.c
Datei (genauer gesagt in derselben Übersetzungseinheit) dorthin, wo sie aufgerufen wird.Wenn einer läuft
./main
wird die Ausgabe seinCalling function inside header
was diese statische Funktion ausgeben sollte. -
Fall 2: Unser Header
header.h
sieht aus wie das:static void FunctionInHeader();
und wir haben auch eine weitere Datei
header.c
die so aussieht:#include <stdio.h> #include "header.h" void FunctionInHeader() { printf("Calling function inside header\n"); }
Dann der folgende Befehl
gcc main.c header.c -o main
wird einen Fehler geben. In diesem Fall
main.c
enthält nur die Deklaration der statischen Funktion, aber die Definition wird in einer anderen Übersetzungseinheit belassen und diestatic
Schlüsselwort verhindert, dass der Code eine zu verknüpfende Funktion definiert -
Fall 3:
Ähnlich wie Fall 2, nur dass jetzt unser Header
header.h
Datei ist:void FunctionInHeader(); // keyword static removed
Dann wird derselbe Befehl wie in Fall 2 ausgeführt und weiter ausgeführt
./main
wird das erwartete Ergebnis liefern. Hier dieFunctionInHeader
Definition befindet sich in einer anderen Übersetzungseinheit, aber der Code, der sie definiert, kann verknüpft werden.
Also zum Schluss:
static keyword prevents the code defining a function to be linked,
when that function is defined in another translation unit than where it is called.
C-Programmierer verwenden das statische Attribut, um Variablen- und Funktionsdeklarationen innerhalb von Modulen zu verbergen, ähnlich wie Sie öffentliche und private Deklarationen in Java und C++ verwenden würden. C-Quelldateien spielen die Rolle von Modulen. Jede mit dem statischen Attribut deklarierte globale Variable oder Funktion ist für dieses Modul privat. Ebenso ist jede globale Variable oder Funktion, die ohne das statische Attribut deklariert wurde, öffentlich und kann von jedem anderen Modul aufgerufen werden. Es gehört zur guten Programmierpraxis, Ihre Variablen und Funktionen nach Möglichkeit mit dem statischen Attribut zu schützen.
human.js
Die Antwort von pmg ist sehr überzeugend. Wenn Sie wissen möchten, wie statische Deklarationen auf Objektebene funktionieren, könnten die folgenden Informationen für Sie interessant sein. Ich habe dasselbe von pmg geschriebene Programm wiederverwendet und es in eine .so(shared object)-Datei kompiliert
Der folgende Inhalt ist nach dem Ablegen der .so-Datei in etwas für Menschen lesbar
0000000000000675 f1: Adresse der Funktion f1
000000000000068c f2: Adresse der Funktion f2(staticc).
Beachten Sie den Unterschied in der Funktionsadresse, es bedeutet etwas. Für eine Funktion, die mit einer anderen Adresse deklariert ist, kann dies sehr gut bedeuten, dass f2 sehr weit entfernt oder in einem anderen Segment der Objektdatei lebt.
Linker verwenden etwas namens PLT (Procedure Linkage Table) und GOT (Global Offsets Table), um Symbole zu verstehen, auf die sie Zugriff haben.
Stellen Sie sich vorerst vor, dass GOT und PLT alle Adressen auf magische Weise binden und ein dynamischer Abschnitt Informationen zu all diesen Funktionen enthält, die für den Linker sichtbar sind.
Nach dem Sichern des dynamischen Abschnitts der .so-Datei erhalten wir eine Reihe von Einträgen, die uns aber nur interessieren f1 und f2 Funktion.
Der dynamische Abschnitt enthält nur den Eintrag für f1 Funktion unter Adresse 0000000000000675 und nicht für f2 !
Num: Wert Größe Typ Bind Vis Ndx Name
9: 0000000000000675 23 FUNC GLOBAL DEFAULT 11 f1
Und das ist es !. Daraus ist klar, dass der Linker beim Auffinden der nicht erfolgreich sein wird f2 funktionieren, da sie nicht im dynamischen Abschnitt der .so-Datei enthalten ist.
Amna Salmann
Wenn der Zugriff auf einige Funktionen eingeschränkt werden muss, verwenden wir das Schlüsselwort static beim Definieren und Deklarieren einer Funktion.
/* file ab.c */
static void function1(void)
{
puts("function1 called");
}
And store the following code in another file ab1.c
/* file ab1.c */
int main(void)
{
function1();
getchar();
return 0;
}
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */
-
Diese Antwort ist nicht sehr hilfreich.
– Fischblog
4. Juni 2020 um 12:21 Uhr
@nightcracker: In C++ gibt es keine “Methoden”. Ich glaube, Sie sind mit Objective-C verwechselt.
– Bo Persson
16. März 2011 um 16:17 Uhr
Nein, ich bin verwirrt mit Python. Eine Funktion innerhalb einer Klasse wird in Python als Methode bezeichnet.
– orlp
16. März 2011 um 16:25 Uhr
mögliches Duplikat von Was ist eine “statische” Funktion? (in C)
– atoMerz
7. März 2014 um 11:53 Uhr