Frage Was bedeutet "statisch" in C?


Ich habe das Wort gesehen static an verschiedenen Stellen im C-Code verwendet; ist das wie eine statische Funktion / Klasse in C # (wo die Implementierung über Objekte verteilt ist)?


854
2018-02-21 06:47


Ursprung


Antworten:


  1. Eine statische Variable in 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 das fremdeste Thema, wenn Sie ein Neuling sind, also 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 druckt:

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 in Fällen, in denen eine Funktion zwischen den Aufrufen einen Zustand beibehalten muss und Sie keine globalen Variablen verwenden möchten. Beachten Sie jedoch, dass diese Funktion nur sehr sparsam verwendet werden sollte. Dadurch ist Ihr Code nicht Thread-sicher und schwerer zu verstehen.

(2) Wird häufig als "Zugriffskontroll" -Funktion verwendet. Wenn eine .c-Datei einige Funktionen implementiert, werden den Benutzern normalerweise nur einige "öffentliche" Funktionen zur Verfügung gestellt. Der Rest seiner Funktionen sollte gemacht werden static, damit der Benutzer nicht auf sie zugreifen kann. Dies ist eine Kapselung, eine gute Praxis.

Zitieren Wikipedia:

In der Programmiersprache C statisch   wird mit globalen Variablen und verwendet   Funktionen, um ihren Umfang auf die   enthaltende Datei. In lokalen Variablen   Mit static wird die Variable gespeichert   im statisch zugewiesenen Speicher   anstatt der automatisch zugewiesenen   Erinnerung. Während die Sprache nicht   diktieren die Implementierung von beiden   Art des Speichers, statisch zugewiesen   Speicher ist typischerweise in Daten reserviert   Segment des Programms bei der Kompilierung   Zeit, während die automatisch   zugeordneter Speicher ist normalerweise   als transienter Call-Stack implementiert.

Sehen Hier und Hier für mehr Details.

Und um deine zweite Frage zu beantworten, ist es nicht wie in C #.

In C ++ jedoch static wird auch verwendet, um Klassenattribute (die von allen Objekten derselben Klasse gemeinsam genutzt werden) und Methoden zu definieren. In C gibt es keine Klassen, daher ist diese Funktion irrelevant.


1221
2018-02-21 06:51



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

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

In diesem Kontext wird angegeben, dass Argumente, die an diese Funktion übergeben werden, ein Array vom Typ sein müssen char mit mindestens 10 Elementen darin. Für weitere Informationen siehe meine Frage Hier.


188
2018-05-01 07:13



Kurze Antwort ... es kommt darauf an.

  1. Statisch definierte lokale Variablen verlieren ihren Wert zwischen Funktionsaufrufen nicht. Mit anderen Worten, sie sind globale Variablen, sind 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.


140
2018-02-21 06:56



Beispiel für eine Datei mit mehreren Dateien

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("");
}

Haupt 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;
}

Zusammenstellung:

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

Deutung

  • Es gibt zwei separate Variablen für si, eine für jede Datei
  • Es gibt eine einzige gemeinsame Variable für i

Wie üblich, je kleiner der Bereich, desto besser, also deklarieren Sie immer Variablen staticWenn du kannst.

In der C-Programmierung werden Dateien häufig zur Darstellung von "Klassen" und static Variablen repräsentieren private statische Mitglieder der Klasse.

Welche Standards sagen darüber

C99 N1256 Entwurf 6.7.1 "Storage-Klasse-Spezifizierer" sagt das static ist ein "Speicherklassenspezifizierer".

6.2.2 / 3 "Verknüpfungen von Kennungen" sagt static impliziert internal linkage:

Wenn die Deklaration eines Dateibereichsbezeichners für ein Objekt oder eine Funktion den Speicherklassenbezeichner statisch enthält, hat der Bezeichner eine interne Verknüpfung.

und 6.2.2 / 2 sagt das internal linkage verhält sich wie in unserem Beispiel:

In dem Satz von Übersetzungseinheiten und Bibliotheken, der ein ganzes Programm bildet, bezeichnet jede Deklaration eines bestimmten Identifizierers 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.

wo "Übersetzungseinheit ist eine Quelldatei nach der Vorverarbeitung.

Wie implementiert GCC es für ELF (Linux)?

Mit dem STB_LOCAL Bindung.

Wenn wir kompilieren:

int i = 0;
static int si = 0;

und zerlegen 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

so ist die Bindung der einzige signifikante Unterschied zwischen ihnen. Value ist nur ihr Offset in die .bss Abschnitt, so erwarten wir, dass es sich unterscheidet.

STB_LOCAL ist auf der ELF-Spezifikation bei dokumentiert 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 mit demselben Namen können in mehreren Dateien vorhanden sein, ohne sich gegenseitig zu stören

was es zu einer perfekten Wahl macht static.

Variablen ohne statische sind STB_GLOBALund die Spezifikation sagt:

Wenn der Verknüpfungseditor mehrere verschiebbare Objektdateien kombiniert, werden mehrere Definitionen von STB_GLOBAL-Symbolen mit demselben Namen nicht zugelassen.

was mit den Linkfehlern bei mehreren nicht statischen Definitionen übereinstimmt.

Wenn wir die Optimierung mit ankurbeln -O3, das si Das Symbol ist vollständig aus der Symboltabelle entfernt: es kann sowieso nicht von außen verwendet werden. TODO warum statische Variablen überhaupt in der Symboltabelle bleiben, wenn es keine Optimierung gibt? Können sie für irgendetwas verwendet werden? Vielleicht zum Debuggen.

Siehe auch

Versuch es selber

Beispiel auf github damit du mit spielen kannst.


45
2018-01-15 13:41



Es kommt darauf an:

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

Die Funktion würde 1, 2, 3 usw. zurückgeben --- die Variable ist nicht auf dem Stapel.

a.c:

static int foo()
{
}

Dies bedeutet, dass diese Funktion nur in dieser Datei Gültigkeit hat. Also a.c und b.c können unterschiedlich sein foo()s, und foo ist nicht freigegebenen Objekten ausgesetzt. Wenn Sie foo in a.c definiert haben, können Sie nicht darauf zugreifen b.c oder von anderen Orten.

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


32
2018-02-21 06:57



Leute sagen immer, dass "statisch" in C zwei Bedeutungen hat. Ich biete eine alternative Betrachtungsweise an, die ihm eine einzige Bedeutung gibt:

  • Wenn Sie "statisch" auf ein Objekt anwenden, wird das Element mit zwei Eigenschaften versehen: (a) Es ist außerhalb des aktuellen Bereichs nicht sichtbar. (b) Es ist hartnäckig.

Der Grund dafür, dass es zwei Bedeutungen zu haben scheint, ist, dass in C jeder Gegenstand, auf den 'statisch' angewendet werden kann hat bereits eine dieser beiden Eigenschaften, so dass es scheint als ob diese bestimmte Verwendung nur die andere beinhaltet.

Betrachten Sie zum Beispiel Variablen. Variablen, die außerhalb von Funktionen deklariert sind, haben bereits eine Persistenz (im Datensegment), so dass das Anwenden von "statisch" sie nur außerhalb des aktuellen Bereichs (Kompilierungseinheit) sichtbar machen kann. Umgekehrt haben Variablen, die innerhalb von Funktionen deklariert sind, bereits außerhalb des aktuellen Gültigkeitsbereichs (Funktion) eine Nichtsichtbarkeit, so dass das Anwenden von "statisch" sie nur persistent machen kann.

Das Anwenden von "statisch" auf Funktionen ist wie das Anwenden auf globale Variablen - Code ist notwendigerweise (zumindest innerhalb der Sprache) persistent, so dass nur die Sichtbarkeit geändert werden kann.

HINWEIS: Diese Kommentare gelten nur für C. In C ++ wird durch das Anwenden von "statisch" auf Klassenmethoden dem Schlüsselwort eine andere Bedeutung zugewiesen. Ähnlich für die C99-Array-Argument-Erweiterung.


18
2018-04-27 13:47



static bedeutet verschiedene Dinge in verschiedenen Kontexten.

  1. Sie können eine statische Variable in einer C-Funktion deklarieren. Diese Variable ist nur in der Funktion sichtbar, verhält sich jedoch wie eine globale Variable, da sie nur einmal initialisiert wird und ihren Wert behält. In diesem Beispiel jedes Mal, wenn Sie anrufen foo() es wird eine zunehmende Anzahl drucken. Die statische Variable wird nur einmal initialisiert.

    void foo ()
    {
    static int i = 0;
    printf("%d", i); i++
    }
    
  2. Eine andere Verwendung von static ist, wenn Sie eine Funktion oder eine globale Variable in einer .c-Datei implementieren, aber nicht möchten, dass das Symbol außerhalb der Datei sichtbar ist .obj generiert von der Datei. z.B.

    static void foo() { ... }
    

12
2018-02-21 06:55



Aus Wikipedia:

In der Programmiersprache C statisch wird mit globalen Variablen und Funktionen verwendet, um ihren Gültigkeitsbereich auf die enthaltene Datei zu setzen. In lokalen Variablen wird statisch verwendet, um die Variable im statisch zugewiesenen Speicher anstelle des automatisch zugewiesenen Speichers zu speichern. Während die Sprache nicht die Implementierung eines beliebigen Speichertyps diktiert, wird statisch zugeordneter Speicher typischerweise in dem Datensegment des Programms zur Kompilierungszeit reserviert, während der automatisch zugewiesene Speicher normalerweise als ein vorübergehender Aufrufstapel implementiert wird.


11
2018-02-21 06:52



Ich hasse es, eine alte Frage zu beantworten, aber ich glaube nicht, dass irgendjemand erwähnt hat, wie K & R es in Abschnitt A4.1 von "Die Programmiersprache C" erklärt.

Kurz gesagt, das Wort static wird mit verwendet zwei Bedeutungen:

  1. Statisch ist eine der zwei Speicherklassen (die andere ist automatisch). Ein statisches Objekt behält seinen Wert zwischen den Aufrufen. Die außerhalb aller Blöcke deklarierten Objekte sind immer statisch und können nicht automatisch erstellt werden.
  2. Aber wenn die static  Stichwort (große Betonung darauf, dass es in Code als Schlüsselwort) wird mit einer Deklaration verwendet, es gibt dem Objekt eine interne Verknüpfung, so dass es nur innerhalb dieser Übersetzungseinheit verwendet werden kann. Wenn das Schlüsselwort jedoch in einer Funktion verwendet wird, ändert es die Speicherklasse des Objekts (das Objekt wäre ohnehin nur in dieser Funktion sichtbar). Das Gegenteil von statisch ist das extern Schlüsselwort, das einem Objekt eine externe Verknüpfung gibt.

Peter Van Der Linden gibt diese zwei Bedeutungen in "Expert C Programming":

  • Innerhalb einer Funktion bleibt der Wert zwischen den Anrufen erhalten.
  • Auf der Funktionsebene, nur in dieser Datei sichtbar.

6
2018-03-30 23:49



Wenn Sie eine Variable in einer Funktion statisch deklarieren, wird ihr Wert nicht auf dem Funktionsaufruf-Stack gespeichert und ist weiterhin verfügbar, wenn Sie die Funktion erneut aufrufen.

Wenn Sie eine globale Variable als statisch deklarieren, wird ihr Gültigkeitsbereich auf die Datei beschränkt, in der Sie sie deklariert haben. Dies ist etwas sicherer als ein normales globales System, das im gesamten Programm gelesen und geändert werden kann.


5
2018-02-21 06:52