1392 Stimmen

Was bedeutet "statisch" in C?

Ich habe das Wort static an verschiedenen Stellen im C-Code verwendet wird; ist dies wie eine statische Funktion/Klasse in C# (bei der die Implementierung auf mehrere Objekte verteilt ist)?

9 Stimmen

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/

1841voto

Eli Bendersky Punkte 246100
  1. Eine statische Variable innerhalb einer Funktion behält ihren Wert zwischen den Aufrufen.
  2. Eine statische globale Variable oder eine Funktion wird nur in der Datei "gesehen", in der sie deklariert ist

(1) ist für Neulinge eher ein Fremdwort, deshalb hier ein Beispiel:

#include <stdio.h>

void foo()
{
    int a = 10;
    static int sa = 10;

    a += 5;
    sa += 5;

    printf("a = %d, sa = %d\n", a, sa);
}

int main()
{
    int i;

    for (i = 0; i < 10; ++i)
        foo();
}

Dies wird gedruckt:

a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60

Dies ist nützlich für Fälle, in denen eine Funktion einen Zustand zwischen Aufrufen beibehalten muss und Sie keine globalen Variablen verwenden möchten. Aber Vorsicht, diese Funktion sollte nur sehr sparsam verwendet werden - sie macht Ihren Code nicht thread-sicher und schwieriger zu verstehen.

(2) Wird häufig als "Zugangskontrollfunktion" verwendet. Wenn Sie eine .c-Datei haben, die eine bestimmte Funktionalität implementiert, werden in der Regel nur einige wenige "öffentliche" Funktionen für Benutzer zugänglich gemacht. Der Rest der Funktionen sollte so gestaltet sein, dass static so dass der Benutzer keinen Zugang zu ihnen hat. Das ist Kapselung, eine gute Praxis.

Zitat Wikipedia :

In der Programmiersprache C ist die statische mit globalen Variablen und Funktionen verwendet, um deren Geltungsbereich auf den enthaltende Datei festzulegen. Bei lokalen Variablen, static wird verwendet, um die Variable in dem statisch zugewiesenen Speicher anstelle des automatisch zugewiesenen Speicher zu speichern. Während die Sprache nicht die Implementierung der beiden Speichertypen vorschreibt Speicherart vorschreibt, wird statisch zugewiesener Speicher normalerweise im Datensegment Segment des Programms zur Kompilierzeit Zeit reserviert, während der automatisch zugewiesene Speicher wird normalerweise als transienter Aufrufstapel implementiert wird.

Und um Ihre zweite Frage zu beantworten: Es ist nicht wie in C#.

In C++ jedoch, static wird auch zur Definition von Klassenattributen (die von allen Objekten der gleichen Klasse gemeinsam genutzt werden) und Methoden verwendet. In C gibt es keine Klassen, so dass diese Funktion irrelevant ist.

187 Stimmen

Pax, der OP weiß nichts über Statik, also schlägst du vor, ihn in den Unterschied zwischen Kompiliereinheiten und Dateien einzuweihen? :-)

149 Stimmen

Eine Kompiliereinheit ist eine einzelne Datei, die der Compiler sieht. Ihre .c-Datei kann andere .c-Dateien enthalten, aber nachdem der Präprozessor die Includes aussortiert hat, sieht der Compiler letztendlich nur eine einzige "Compilation Unit".

3 Stimmen

David, wenn du neu in C bist, sollte dich dieses Problem überhaupt nicht stören. Es stört 99,9 % der C-Programmierer sowieso nicht.

288voto

dreamlax Punkte 91447

Es gibt noch eine weitere Verwendung, die hier nicht behandelt wird, und zwar als Teil einer Array-Typ-Deklaration als Argument für eine Funktion:

int someFunction(char arg[static 10])
{
    ...
}

In diesem Zusammenhang bedeutet dies, dass Argumente, die an diese Funktion übergeben werden, ein Array vom Typ char mit mindestens 10 Elementen darin. Für weitere Informationen siehe meine Frage aquí .

5 Stimmen

Ich hätte nicht gedacht, dass C Array-Argumente hat? Linus Torvalds schimpft wütend über Leute, die das tun.

22 Stimmen

@jamieb: C hat keine Array-Argumente, aber diese spezielle Syntax bedeutet, dass die Funktion erwartet arg[0] bis arg[9] Werte zu haben (was auch bedeutet, dass die Funktion keinen Null-Zeiger akzeptiert). Compiler könnten diese Information in irgendeiner Weise zur Optimierung nutzen, und statische Analysatoren können diese Information nutzen, um sicherzustellen, dass die Funktion niemals einen Null-Zeiger erhält (oder, wenn sie es erkennen kann, ein Array mit weniger Elementen als angegeben).

26 Stimmen

@Qix -- Dies war eine neue überladene Bedeutung, die der static in C99. Es ist mehr als anderthalb Jahrzehnte alt, aber nicht alle Compiler-Autoren haben alle C99-Funktionen übernommen - so dass C99 als Ganzes weitgehend unbekannt bleibt.

204voto

cmcginty Punkte 106764

Kurze Antwort ... Es kommt darauf an.

  1. Statisch definierte lokale Variablen verlieren ihren Wert zwischen Funktionsaufrufen nicht. Mit anderen Worten: Sie sind globale Variablen, aber auf die lokale Funktion beschränkt, in der sie definiert sind.

  2. Statische globale Variablen sind außerhalb der C-Datei, in der sie definiert sind, nicht sichtbar.

  3. Statische Funktionen sind außerhalb der C-Datei, in der sie definiert sind, nicht sichtbar.

10 Stimmen

Bedeutet "statische Funktion" und "private Funktion" also dasselbe? Sind auch "statische globale Variablen" und "private globale Variablen" dasselbe?

47 Stimmen

Hier geht es um C. In C gibt es kein Privat/Öffentlich.

32 Stimmen

@user1599964 obwohl es keine private in C ist Ihre Analogie gut: statisch macht Dinge "privat" für eine bestimmte Datei. Und Dateien in C entsprechen oft den Klassen in C++.

85voto

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

41voto

Artyom Punkte 29856

Das kommt darauf an:

int foo()
{
   static int x;
   return ++x;
}

Die Funktion würde 1, 2, 3, usw. zurückgeben. --- die Variable befindet sich nicht auf dem Stack.

a.c:

static int foo()
{
}

Das bedeutet, dass diese Funktion nur in dieser Datei gültig ist. So können a.c und b.c unterschiedliche foo() s, und foo ist nicht für gemeinsam genutzte Objekte freigegeben. Wenn Sie also foo in a.c definieren, können Sie es nicht von b.c oder von jedem anderen Ort.

In den meisten C-Bibliotheken sind alle "privaten" Funktionen statisch und die meisten "öffentlichen" Funktionen sind es nicht.

20 Stimmen

+1 für die Erwähnung von x nicht auf dem Stack oder Heap. Es befindet sich im statischen Speicherbereich.

1 Stimmen

@Gob00st statischer Speicherplatz? Sie meinten "Datensegment"...?

0 Stimmen

@YoushaAleayoub Siehe este y este .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X