it-swarm.com.de

Was bedeutet "statisch" in C?

Ich habe gesehen, dass das Wort static an verschiedenen Stellen im C-Code verwendet wurde. Ist dies wie eine statische Funktion/Klasse in C # (wo die Implementierung von Objekten gemeinsam genutzt wird)? 

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

(1) ist das fremdere 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 einen Status zwischen Aufrufen beibehalten muss und Sie keine globalen Variablen verwenden möchten. Beachten Sie jedoch, dass diese Funktion sehr sparsam eingesetzt werden sollte - dadurch wird Ihr Code nicht Thread-sicher und ist schwieriger zu verstehen.

(2) Wird häufig als "Zugriffskontroll" -Funktion verwendet. Wenn Sie über eine .c-Datei verfügen, die einige Funktionen implementiert, werden Benutzern normalerweise nur wenige "öffentliche" Funktionen zur Verfügung gestellt. Die restlichen Funktionen sollten static sein, damit der Benutzer nicht auf sie zugreifen kann. Dies ist Kapselung, eine gute Praxis.

Zitieren Wikipedia :

In der Programmiersprache C statisch wird mit globalen Variablen und .__ verwendet. Funktionen, um ihren Gültigkeitsbereich auf die .__ festzulegen. enthaltende Datei. In lokalen Variablen gilt statisch wird verwendet, um die Variable zu speichern im statisch zugewiesenen Speicher anstelle des automatisch zugewiesenen Erinnerung. Während die Sprache nicht Diktieren Sie die Implementierung von Speicherart, statisch zugewiesen Speicher wird normalerweise in Daten reserviert Segment des Programms beim Kompilieren Zeit, während die automatisch zugewiesener Speicher ist normalerweise als Transient Call Stack implementiert.

Siehe hier und hier für weitere Details.

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

In C++ wird static jedoch 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.

1328
Eli Bendersky

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

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

In diesem Zusammenhang gibt dies an, dass die an diese Funktion übergebenen Argumente ein Array vom Typ char mit mindestens 10 Elementen sein müssen. Weitere Informationen finden Sie in meiner Frage hier .

209
dreamlax

Kurze Antwort ... es kommt darauf an.

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

149
cmcginty

Beispiel für mehrere Dateivariablen

Hier zeige ich, wie sich statisch auf den Umfang der Funktionsdefinitionen in mehreren Dateien 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("");
}

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

GitHub Upstream .

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

Deutung

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

Je kleiner der Gültigkeitsbereich, desto besser, wie üblich, deklarieren Sie die Variablen static, wenn Sie können.

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

Welche Normen sagen dazu aus

C99 N1256 draft 6.7.1 "Speicherklassenspezifizierer" besagt, dass static ein "Speicherklassenspezifizierer" ist.

6.2.2/3 "Verknüpfungen von Bezeichnern" besagt, dass staticinternal linkage impliziert:

Wenn die Deklaration eines Dateibereichs-Bezeichners für ein Objekt oder eine Funktion den Speicherklassenspezifizierer static enthält, hat der Bezeichner eine interne Verknüpfung.

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

In dem Satz von Übersetzungseinheiten und Bibliotheken, der ein gesamtes Programm darstellt, bezeichnet jede Deklaration eines bestimmten Bezeichners mit externer Verknüpfung das gleiche Objekt oder die gleiche Funktion. Innerhalb einer Übersetzungseinheit bezeichnet jede Deklaration eines Bezeichners mit interner Verknüpfung das gleiche Objekt oder die gleiche Funktion. 

wo "Übersetzungseinheit ist eine Quelldatei nach der Vorverarbeitung.

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

Mit der 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

die Bindung ist also der einzige signifikante Unterschied zwischen ihnen. Value ist nur deren Versatz in den .bss-Abschnitt, wir erwarten also, dass es unterschiedlich ist.

STB_LOCAL ist auf der ELF-Spezifikation unter http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html dokumentiert:

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 vorhanden sein, ohne sich gegenseitig zu stören

dies macht es zur perfekten Wahl, um static darzustellen.

Variablen ohne statisch sind STB_GLOBAL und die Spezifikation sagt:

Wenn der Link-Editor mehrere verschiebbare Objektdateien kombiniert, sind keine mehrfachen Definitionen von STB_GLOBAL-Symbolen mit demselben Namen zulässig. 

was mit den Verbindungsfehlern bei mehreren nicht statischen Definitionen kohärent ist.

Wenn Sie die Optimierung mit -O3 starten, wird das si-Symbol vollständig aus der Symboltabelle entfernt: Es kann sowieso nicht von außen verwendet werden. TODO Warum sollten statische Variablen überhaupt in der Symboltabelle bleiben, wenn keine Optimierung erfolgt? Können sie für irgendetwas verwendet werden? Vielleicht zum Debuggen.

Siehe auch

Anonyme C++ - Namespaces

In C++ möchten Sie möglicherweise anonyme Namespaces anstelle von static verwenden, wodurch ein ähnlicher Effekt erzielt wird, die Typdefinitionen jedoch ausgeblendet werden: Unbenannte/anonyme Namespaces vs. statische Funktionen

Es hängt davon ab, ob:

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

Die Funktion würde 1, 2, 3 usw. zurückgeben. Die Variable befindet sich nicht im Stapel.

a.c:

static int foo()
{
}

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

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

34
Artyom

Die Leute sagen immer wieder, dass "statisch" in C zwei Bedeutungen hat. Ich biete eine alternative Sichtweise an, die eine einzige Bedeutung hat:

  • Die Anwendung von "statisch" auf ein Element erzwingt, dass das Element zwei Eigenschaften hat: (a) Es ist außerhalb des aktuellen Bereichs nicht sichtbar. (b) Es ist beständig.

Der Grund, warum es zwei Bedeutungen zu haben scheint, ist, dass in C jedes Element, auf das 'static' angewendet werden kann, hat bereits eine dieser beiden Eigenschaften hat, so dass scheint als ob das wäre bestimmte Verwendung bezieht nur den anderen ein.

Betrachten Sie zum Beispiel Variablen. Variablen, die außerhalb von Funktionen deklariert wurden, sind bereits persistent (im Datensegment). Daher kann das Anwenden von 'static' sie nur außerhalb des aktuellen Bereichs (Compilation Unit) sichtbar machen. Im Gegensatz dazu haben Variablen, die innerhalb von Funktionen deklariert sind, bereits außerhalb des aktuellen Gültigkeitsbereichs (Funktion) keine Sichtbarkeit, sodass das Anwenden von "static" sie nur persistent machen kann.

Das Anwenden von "statisch" auf Funktionen ist genauso wie das Anwenden auf globale Variablen - Code ist notwendigerweise dauerhaft (zumindest in der Sprache), sodass nur die Sichtbarkeit geändert werden kann.

HINWEIS: Diese Kommentare gelten nur für C. In C++ hat das Anwenden von 'static' auf Klassenmethoden dem Schlüsselwort tatsächlich eine andere Bedeutung. Ähnlich für die Erweiterung des C99-Array-Arguments.

19
PMar

Von Wikipedia:

In der Programmiersprache C wird static mit globalen Variablen und Funktionen verwendet, um deren Gültigkeitsbereich auf die enthaltende Datei festzulegen. In lokalen Variablen wird statisch verwendet, um die Variable im statisch zugewiesenen Speicher statt im automatisch zugewiesenen Speicher zu speichern. Während die Sprache die Implementierung eines beliebigen Speichertyps nicht vorschreibt, wird statisch zugewiesener Speicher typischerweise im Datensegment des Programms zur Kompilierzeit reserviert, während der automatisch zugewiesene Speicher normalerweise als Transient Call Stack implementiert wird.

12
OscarRyz

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, da sie nur einmal initialisiert wird und ihren Wert behält. In diesem Beispiel wird bei jedem Aufruf von foo() eine aufsteigende Nummer gedruckt. Die statische Variable wird nur einmal initialisiert.

    void foo ()
    {
    static int i = 0;
    printf("%d", i); i++
    }
    
  2. Static kann auch verwendet werden, wenn Sie eine Funktion oder globale Variable in einer C-Datei implementieren, das Symbol jedoch nicht außerhalb des von der Datei generierten .obj sichtbar sein soll. z.B.

    static void foo() { ... }
    
12
m-sharp

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

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

  1. Static ist eine der zwei Speicherklassen (die andere ist Automatic). Ein statisches Objekt behält seinen Wert zwischen Aufrufen. Die außerhalb aller Blöcke deklarierten Objekte sind immer statisch und können nicht automatisch erstellt werden.
  2. Wenn jedoch das staticSchlüsselwort (es wird großer Wert darauf gelegt wird, dass es in Code als Schlüsselwort verwendet wird) mit einer Deklaration verwendet wird, erhält dieses Objekt eine interne Verknüpfung, sodass 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 sowieso nur innerhalb dieser Funktion sichtbar). Das Gegenteil von statisch ist das Schlüsselwort extern, das einem Objekt eine externe Verknüpfung gibt.

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

  • In einer Funktion wird der Wert zwischen den Aufrufen beibehalten.
  • Auf der Funktionsebene nur in dieser Datei sichtbar.
6
nobism

Wenn Sie eine Variable in einer Funktion statisch deklarieren, wird ihr Wert nicht auf dem Funktionsaufruf-Stack gespeichert und ist nach dem erneuten Aufruf der Funktion weiterhin verfügbar.

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 regulärer Globus, der im gesamten Programm gelesen und geändert werden kann.

5
Sam Hoice

In C hat statisch je nach Anwendungsbereich zwei Bedeutungen. Wenn im globalen Bereich ein Objekt auf Dateiebene deklariert wird, bedeutet dies, dass dieses Objekt nur in dieser Datei sichtbar ist.

In jedem anderen Bereich wird ein Objekt deklariert, das seinen Wert zwischen den verschiedenen Zeitpunkten behält, zu denen der jeweilige Bereich eingegeben wird. Wenn zum Beispiel ein int innerhalb einer Prozedur gelöscht wird:

void procedure(void)
{
   static int i = 0;

   i++;
}

der Wert von 'i' wird beim ersten Aufruf der Prozedur mit Null initialisiert, und der Wert wird bei jedem nachfolgenden Aufruf der Prozedur beibehalten. Wenn 'i' gedruckt wird, wird eine Folge von 0, 1, 2, 3, ... ausgegeben.

5
Gary

Wenn Sie dies in einer mytest.c-Datei angeben:

static int my_variable;

Dann kann diese Variable nur aus dieser Datei gesehen werden. Die Variable kann nicht an einen anderen Ort exportiert werden.

Wenn Sie innerhalb einer Funktion deklarieren, behält der Wert der Variablen bei jedem Aufruf der Funktion ihren Wert.

Eine statische Funktion kann nicht außerhalb der Datei exportiert werden. In einer * .c-Datei verbergen Sie also die Funktionen und Variablen, wenn Sie sie für statisch erklären.

4
ant2009

Es ist wichtig zu beachten, dass statische Variablen in Funktionen beim ersten Eintrag in diese Funktion initialisiert werden und auch nach Beendigung ihres Aufrufs bestehen bleiben. Bei rekursiven Funktionen wird die statische Variable nur einmal initialisiert und bleibt auch bei allen rekursiven Aufrufen erhalten, auch wenn der Aufruf der Funktion abgeschlossen ist.

Wenn die Variable außerhalb einer Funktion erstellt wurde, bedeutet dies, dass der Programmierer nur die Variable in der Quelldatei verwenden kann, in der die Variable deklariert wurde.

3
Starhowl

Statische Variablen in C haben die Lebensdauer des Programms.

Wenn sie in einer Funktion definiert sind, haben sie einen lokalen Gültigkeitsbereich, d. H. Sie können nur innerhalb dieser Funktionen aufgerufen werden. Der Wert statischer Variablen wird zwischen Funktionsaufrufen beibehalten.

Zum Beispiel:

void function()
{
    static int var = 1;
    var++;
    printf("%d", var);
}

int main()
{
    function(); // Call 1
    function(); // Call 2
}

Im obigen Programm wird var im Datensegment gespeichert. Seine Lebensdauer ist das gesamte C-Programm.

Nach dem Funktionsaufruf 1 wird var 2. Nach Funktionsaufruf 2 wird var 3.

Der Wert von var wird zwischen Funktionsaufrufen nicht zerstört.

Wenn var zwischen einer nicht statischen und einer lokalen Variablen hätte, würde sie im Stapelsegment im C-Programm gespeichert werden. Da der Stack-Frame der Funktion nach der Rückkehr der Funktion zerstört wird, wird auch der Wert von var zerstört.

Initialisierte statische Variablen werden im Datensegment des C-Programms gespeichert, während nicht initialisierte Variablen im BSS-Segment gespeichert werden.

Weitere Informationen zu statisch: Wenn eine Variable global und statisch ist, hat sie die Lebensdauer des C-Programms, aber den Dateizugriff. Es ist nur in dieser Datei sichtbar.

Um dies zu versuchen:

file1.c

static int x;

int main()
{
    printf("Accessing in same file%d", x):
}

file2.c

    extern int x;
    func()
    {
        printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c
    }

run gcc -c file1.c

gcc -c file2.c

Versuchen Sie jetzt, sie mit zu verknüpfen:

gcc -o output file1.o file2.o

Es würde einen Linker-Fehler geben, da x den Dateibereich von file1.c hat und der Linker den in file2.c verwendeten Verweis auf Variable x nicht auflösen kann.

Verweise:

  1. http://en.wikipedia.org/wiki/Translation_unit_(programming)
  2. http://en.wikipedia.org/wiki/Call_stack
3
Sahil Manchanda

Eine statische Variable ist eine spezielle Variable, die Sie in einer Funktion verwenden können. Sie speichert die Daten zwischen Aufrufen und löscht sie nicht zwischen Aufrufen. Zum Beispiel:

void func(){
    static int count; // If you don't declare its value, the value automatically initializes to zero
    printf("%d, ", count);
    count++;
}

void main(){
    while(true){
        func();
    }
}

Die Ausgabe:

0, 1, 2, 3, 4, 5, ...

2
Yagel

Ein statischer Variablenwert bleibt zwischen verschiedenen Funktionsaufrufen bestehen, und sein Gültigkeitsbereich ist auf den lokalen Block beschränkt. Eine statische Variable wird immer mit dem Wert 0 initialisiert

1
Jonathon

Es gibt zwei Fälle:

(1) Lokale Variablen, die als static deklariert wurden: Im Datensegment anstelle des Stapels zugewiesen. Ihr Wert bleibt erhalten, wenn Sie die Funktion erneut aufrufen.

(2) Globale Variablen oder Funktionen, die als static deklariert wurden: Unsichtbar außerhalb der Übersetzungseinheit (d. H. Sind lokale Symbole in der Symboltabelle während der Verknüpfung).

1
Jonny Kong

In der C-Programmierung ist statisch ein reserviertes Schlüsselwort, das sowohl die Lebensdauer als auch die Sichtbarkeit steuert. Wenn wir eine Variable innerhalb einer Funktion als statisch deklarieren, ist sie nur in dieser Funktion sichtbar. In dieser Verwendung beginnt die Lebensdauer dieser statischen Variablen, wenn eine Funktion aufgerufen wird, und wird nach der Ausführung dieser Funktion zerstört. Sie können folgendes Beispiel sehen:

#include<stdio.h> 
int counterFunction() 
{ 
  static int count = 0; 
  count++; 
  return count; 
} 

int main() 
{ 
  printf("First Counter Output = %d\n", counterFunction()); 
  printf("Second Counter Output = %d ", counterFunction()); 
  return 0; 
}

Das obige Programm gibt uns diese Ausgabe:
Erster Zählerausgang = 1 
Zweiter Zählerausgang = 1 
Sobald wir die Funktion aufrufen, wird die Zählung = 0 initialisiert. Wenn Sie die counterFunction ausführen, wird die Zählvariable gelöscht.

0
Makdia Hussain