Wat betekent “statisch” in C?

Ik heb het woord staticop verschillende plaatsen in C-code gebruikt; is dit als een statische functie/klasse in C# (waar de implementatie wordt gedeeld door objecten)?


Antwoord 1, autoriteit 100%

  1. Een statische variabele binnen een functie behoudt zijn waarde tussen aanroepen.
  2. Een statische globale variabele of een functie wordt alleen “gezien” in het bestand waarin het is gedeclareerd

(1) is het meer buitenlandse onderwerp als je een nieuweling bent, dus hier is een voorbeeld:

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

Hiermee wordt afgedrukt:

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

Dit is handig voor gevallen waarin een functie een bepaalde status moet behouden tussen aanroepen en u geen globale variabelen wilt gebruiken. Pas echter op, deze functie moet zeer spaarzaam worden gebruikt – het maakt uw code niet thread-safe en moeilijker te begrijpen.

(2) Wordt veel gebruikt als een “toegangscontrole”-functie. Als u een .c-bestand hebt dat een bepaalde functionaliteit implementeert, stelt het gewoonlijk slechts een paar “openbare” functies voor gebruikers beschikbaar. De rest van zijn functies moeten staticworden gemaakt, zodat de gebruiker er geen toegang toe heeft. Dit is inkapseling, een goede gewoonte.

Citeer Wikipedia:

In de programmeertaal C, statisch
wordt gebruikt met globale variabelen en
functies om hun bereik in te stellen op de
bestand bevatten. In lokale variabelen,
static wordt gebruikt om de variabele op te slaan
in het statisch toegewezen geheugen
in plaats van de automatisch toegewezen
geheugen. Hoewel de taal dat niet doet
dicteren de implementatie van een van beide
type geheugen, statisch toegewezen
geheugen is meestal gereserveerd in data
segment van het programma bij compile
tijd, terwijl de automatisch
toegewezen geheugen is normaal
geïmplementeerd als een tijdelijke oproepstack.

En om je tweede vraag te beantwoorden, het is niet zoals in C#.

In C++ wordt staticechter ook gebruikt om klasseattributen (gedeeld tussen alle objecten van dezelfde klasse) en methoden te definiëren. In C zijn er geen klassen, dus deze functie is niet relevant.


Antwoord 2, autoriteit 15%

Er is nog een gebruik dat hier niet wordt behandeld, en dat is als onderdeel van een array-typedeclaratie als argument voor een functie:

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

In deze context specificeert dit dat argumenten die aan deze functie worden doorgegeven een array van het type charmoeten zijn met ten minste 10 elementen erin. Voor meer info zie mijn vraag hier.


Antwoord 3, autoriteit 11%

Kort antwoord … het hangt ervan af.

  1. Statisch gedefinieerde lokale variabelen verliezen hun waarde niet tussen functieaanroepen. Met andere woorden, het zijn globale variabelen, maar beperkt tot de lokale functie waarin ze zijn gedefinieerd.

  2. Statische globale variabelen zijn niet zichtbaar buiten het C-bestand waarin ze zijn gedefinieerd.

  3. Statische functies zijn niet zichtbaar buiten het C-bestand waarin ze zijn gedefinieerd.


4, Autoriteit 4%

Variabele scope voor multi-bestand

Hier illustreer ik hoe statische invloed is op de reikwijdte van functiedefinities in meerdere bestanden.

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 Upstream .

compileren en uitvoeren:

gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o

Uitgang:

m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2

interpretatie

  • Er zijn twee afzonderlijke variabelen voor si, één voor elk bestand
  • Er is een enkele gedeelde variabele voor i

Zoals gewoonlijk, hoe kleiner de scope, hoe beter, dus altijd variabelen verklaren staticals u kunt.

In C-programmering worden bestanden vaak gebruikt om “klassen” weer te geven en staticvariabelen vertegenwoordigen particuliere statische leden van de klasse.

Welke normen zeggen erover

C99 N1256 Draft 6.7.1 “Opslagklassespecificaties” zegt dat staticeen “opslagklassespecificator” is.

6.2.2 / 3 “-oppelingen van identificatoren” zegt staticImpliceert internal linkage:

Als de verklaring van een bestandscope-ID voor een object of een functie de opslagklasse-specificatorstatisch bevat, heeft de identifier de interne koppeling.

en 6.2.2 / 2 zegt dat internal linkagegedraagt ​​in ons voorbeeld:

In de reeks vertaaleenheden en bibliotheken die een volledig programma vormt, duidt elke verklaring van een bepaalde identifier met externe koppeling hetzelfde object of functie aan. Binnen één vertaaleenheid geeft elke verklaring van een identifier met interne koppeling hetzelfde object of functie aan.

waar “vertaaleenheid een bronbestand is na preprocessing.

hoe GCC het implementeert voor elf (Linux)?

Met de STB_LOCALbinding.

Als we compileren:

int i = 0;
static int si = 0;

en demonteer de symbooltabel met:

readelf -s main.o

De uitvoer bevat:

Num:    Value          Size Type    Bind   Vis      Ndx Name
  5: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    4 si
 10: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    4 i

dus de binding is het enige significante verschil tussen beide. Valueis slechts hun offset in de sectie .bss, dus we verwachten dat deze zal verschillen.

STB_LOCALis gedocumenteerd op de ELF-specificatie op http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html:

STB_LOCAL Lokale symbolen zijn niet zichtbaar buiten het objectbestand dat hun definitie bevat. Lokale symbolen met dezelfde naam kunnen in meerdere bestanden voorkomen zonder elkaar te hinderen

wat het een perfecte keuze maakt om staticweer te geven.

Variabelen zonder statische zijn STB_GLOBAL, en de specificatie zegt:

Als de linkeditor meerdere verplaatsbare objectbestanden combineert, staat het niet meerdere definities van STB_GLOBAL-symbolen met dezelfde naam toe.

wat coherent is met de linkfouten op meerdere niet-statische definities.

Als we de optimalisatie opvoeren met -O3, wordt het si-symbool volledig uit de symbooltabel verwijderd: het kan sowieso niet van buitenaf worden gebruikt. TODO waarom zou je statische variabelen in de symbolentabel houden als er geen optimalisatie is? Zijn ze ergens voor te gebruiken? Misschien om te debuggen.

Zie ook

C++ anonieme naamruimten

In C++ wilt u misschien anonieme naamruimten gebruiken in plaats van statische, wat een vergelijkbaar effect bereikt, maar typedefinities verder verbergt: Naamloze/anonieme naamruimten vs. statische functies


Antwoord 5, autoriteit 2%

Het hangt ervan af:

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

De functie retourneert 1, 2, 3, etc. — de variabele staat niet op de stapel.

a.c:

static int foo()
{
}

Het betekent dat deze functie alleen bereik heeft in dit bestand. Dus a.c en b.c kunnen verschillende foo()s hebben, en foo wordt niet blootgesteld aan gedeelde objecten. Dus als je foo definieerde in a.c, had je er geen toegang toe vanaf b.cof vanaf andere plaatsen.

In de meeste C-bibliotheken zijn alle “private” functies statisch en de meeste “openbare” niet.


Antwoord 6, autoriteit 2%

Mensen blijven zeggen dat ‘statisch’ in C twee betekenissen heeft. Ik bied een alternatieve manier om het te bekijken die het een enkele betekenis geeft:

  • Het toepassen van ‘statisch’ op een item dwingt dat item twee eigenschappen te hebben: (a) Het is niet zichtbaar buiten het huidige bereik; (b) Het is hardnekkig.

De reden dat het twee betekenissen lijkt te hebben, is dat in C elk item waarop ‘statisch’ kan worden toegepast al een van deze twee eigenschappen heeft, dus het lijktem>alsof dat specifieke gebruik alleen het andere betreft.

Overweeg bijvoorbeeld variabelen. Variabelen die buiten functies zijn gedeclareerd, hebben al persistentie (in het gegevenssegment), dus het toepassen van ‘statisch’ kan ze alleen niet zichtbaar maken buiten het huidige bereik (compilatie-eenheid). Omgekeerd zijn variabelen die binnen functies zijn gedeclareerd al niet zichtbaar buiten het huidige bereik (functie), dus het toepassen van ‘statisch’ kan ze alleen persistent maken.

Het toepassen van ‘statisch’ op functies is hetzelfde als het toepassen op globale variabelen – code is noodzakelijkerwijs persistent (althans binnen de taal), dus alleen de zichtbaarheid kan worden gewijzigd.

OPMERKING: deze opmerkingen zijn alleen van toepassing op C. In C++ geeft het toepassen van ‘static’ op klassenmethoden het trefwoord echt een andere betekenis. Hetzelfde geldt voor de C99 array-argumentextensie.


Antwoord 7

staticbetekent verschillende dingen in verschillende contexten.

  1. Je kunt een statische variabele declareren in een C-functie. Deze variabele is alleen zichtbaar in de functie, maar gedraagt zich als een globale variabele omdat deze slechts één keer wordt geïnitialiseerd en zijn waarde behoudt. In dit voorbeeld zal elke keer dat u foo()aanroept, een oplopend getal worden afgedrukt. De statische variabele wordt slechts eenmaal geïnitialiseerd.

    void foo ()
    {
    static int i = 0;
    printf("%d", i); i++
    }
    
  2. Een ander gebruik van static is wanneer u een functie of globale variabele in een .c-bestand implementeert, maar niet wilt dat het symbool zichtbaar is buiten de .objdie door het bestand wordt gegenereerd . bijv.

    static void foo() { ... }
    

Antwoord 8

Ik vind het vervelend om een oude vraag te beantwoorden, maar ik denk dat niemand heeft vermeld hoe K&R het uitlegt in sectie A4.1 van “De programmeertaal C”.

Kortom, het woord statisch wordt gebruikt met tweebetekenissen:

  1. Statisch is een van de twee opslagklassen (de andere is
    automatisch). Een statisch object behoudt zijn waarde tussen aanroepen. De objecten die buiten alle blokken worden gedeclareerd, zijn altijd statisch en kunnen niet automatisch worden gemaakt.
  2. Maar wanneer het staticzoekwoord(grote nadruk op het gebruik ervan in
    code als trefwoord) wordt gebruikt met een declaratie, geeft het dat object een interne koppeling, zodat het alleen binnen die vertaaleenheid kan worden gebruikt. Maar als het sleutelwoord in een functie wordt gebruikt, verandert het de opslagklasse van het object (het object zou sowieso alleen binnen die functie zichtbaar zijn). Het tegenovergestelde van statisch is het trefwoord extern, dat een object externe koppeling geeft.

Peter Van Der Linden geeft deze twee betekenissen in “Expert C Programming”:

  • Binnen een functie, behoudt zijn waarde tussen oproepen.
  • op het functieniveau, alleen zichtbaar in dit bestand.

9

Als u een variabele in een functie static declareert, wordt de waarde ervan niet opgeslagen op de functie Functie-oproep en is deze nog steeds beschikbaar wanneer u de functie opnieuw belt.

Als u een wereldwijde variabele statisch verklaart, wordt de reikwijdte beperkt tot binnen het bestand waarin u het heeft verklaard. Dit is enigszins veiliger dan een normaal globaal dat gedurende uw gehele programma kan worden gelezen en gewijzigd.


10

In C, static heeft twee betekenissen, afhankelijk van het bereik van het gebruik ervan. In de wereldwijde reikwijdte, wanneer een object op het bestandsniveau wordt gedeclareerd, betekent dit dat het object alleen zichtbaar is in dat bestand.

Bij elke andere reikwijdte verklaart het een object dat zijn waarde tussen de verschillende tijdstippen behoudt dat de specifieke reikwijdte is ingevoerd. Als een INT bijvoorbeeld wordt gedesneden in een procedure:

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

De waarde van ‘I’ wordt geïnitialiseerd naar nul op de eerste oproep naar de procedure, en de waarde wordt behouden elke volgende tijd die de procedure wordt genoemd. Als ‘i’ werd afgedrukt, zou het een reeks van 0, 1, 2, 3, …

uitvoeren


11

Het is belangrijk op te merken dat statische variabelen in functies in de eerste keer in die functie worden geïnitialiseerd en blijven bestaan, zelfs nadat hun oproep is voltooid; In het geval van recursieve functies wordt de statische variabele slechts één keer geïnitialiseerd en blijft evengoed over alle recursieve oproepen en zelfs nadat de oproep van de functie is voltooid.

Als de variabele buiten een functie is gemaakt, betekent dit dat de programmeur alleen in staat is om de variabele in het bronbestand te gebruiken, de variabele is aangegeven.


Antwoord 12

Statische variabelen in C hebben de levensduur van het programma.

Als ze in een functie zijn gedefinieerd, hebben ze een lokaal bereik, d.w.z. ze zijn alleen toegankelijk binnen die functies. De waarde van statische variabelen blijft behouden tussen functieaanroepen.

Bijvoorbeeld:

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

In het bovenstaande programma wordt varopgeslagen in het datasegment. Zijn levensduur is het hele C-programma.

Na functieaanroep 1 wordt var2. Na functieaanroep 2 wordt var3.

De waarde van varwordt niet vernietigd tussen functieaanroepen.

Als vareen niet-statische en lokale variabele had, zou deze worden opgeslagen in het stapelsegment in het C-programma. Aangezien het stapelframe van de functie wordt vernietigd nadat de functie is geretourneerd, wordt ook de waarde van varvernietigd.

Geïnitialiseerde statische variabelen worden opgeslagen in het datasegment van het C-programma, terwijl niet-geïnitialiseerde variabelen worden opgeslagen in het BSS-segment.

Nog meer informatie over statisch: als een variabele globaal en statisch is, heeft deze de levensduur van het C-programma, maar heeft deze een bestandsomvang. Het is alleen zichtbaar in dat bestand.

Om dit te proberen:

bestand1.c

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

bestand2.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

Probeer ze nu te koppelen met:

gcc -o output file1.o file2.o

Het zou een linkerfout opleveren omdat x de bestandsomvang van file1.c heeft en de linker de verwijzing naar variabele x die in file2.c wordt gebruikt, niet kan oplossen.

Referenties:

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

Antwoord 13

Als je dit aangeeft in een mytest.cbestand:

static int my_variable;

Dan is deze variabele alleen vanuit dit bestand te zien. De variabele kan nergens anders worden geëxporteerd.

Als je binnen een functie declareert, behoudt de waarde van de variabele zijn waarde elke keer dat de functie wordt aangeroepen.

Een statische functie kan niet van buiten het bestand worden geëxporteerd. Dus in een *.c-bestand verberg je de functies en variabelen als je ze statisch verklaart.


Antwoord 14

Een statische variabele is een speciale variabele die u in een functie kunt gebruiken, en bewaart de gegevens tussen aanroepen en verwijdert deze niet tussen aanroepen. Bijvoorbeeld:

void func(void) {
    static int count; // If you don't declare its value, it is initialized with zero
    printf("%d, ", count);
    ++count;
}
int main(void) {
    while(true) {
        func();
    }
    return 0;
}

De uitvoer:

0, 1, 2, 3, 4, 5, …


Antwoord 15

Een statische variabele waarde blijft bestaan ​​tussen verschillende functie-oproepen Andits Scope is beperkt tot het lokale blok
Een statische var initialiseert altijd met waarde 0


16

Er zijn 2 gevallen:

(1) Lokale variabelen gedeclareerd static: toegewezen in het gegevenssegment in plaats van stapel. De waarde ervan behoudt wanneer u de functie opnieuw belt.

(2) Global Variabelen of functies gedeclareerd static: onzichtbare buiten compilatie-eenheid (d.w.z. zijn lokale symbolen in symbooltabel tijdens het koppelen).


17

Statische variabelen hebben een eigenschap van Behoud hun waarde , zelfs nadat ze buiten hun bereik zijn! Vandaar dat statische variabelen hun vorige waarde in hun vorige scope behouden en worden niet opnieuw geïnitialiseerd in de nieuwe reikwijdte.

Bekijk dit bijvoorbeeld –
Een statische int variabele blijft in het geheugen terwijl het programma draait. Een normale of automatische variabele wordt vernietigd wanneer een functie-oproep waar de variabele is aangegeven, is voorbij.

#include<stdio.h> 
int fun() 
{ 
  static int count = 0; 
  count++; 
  return count; 
} 
int main() 
{ 
  printf("%d ", fun()); 
  printf("%d ", fun()); 
  return 0; 
}

Dit wordt uitgevoerd: 1 2

Zoals 1 verblijven in het geheugen zoals het is aangegeven statisch

Statische variabelen (zoals globale variabelen) worden geïnitialiseerd als 0 indien niet expliciet geïnitialiseerd. In het onderstaande programma wordt bijvoorbeeld de waarde van x afgedrukt als 0, terwijl de waarde van y iets afval is. Zie dit voor meer informatie.

#include <stdio.h> 
int main() 
{ 
    static int x; 
    int y; 
    printf("%d \n %d", x, y); 
}

Dit wordt uitgevoerd: 0
[SOME_GARAGE_VALUE]

Dit zijn de belangrijkste die ik vond die niet hierboven uitgelegd voor een newbie!


18

In C-programmering, staticis een gereserveerd sleutelwoord dat zowel het leven zowel bestuurt als zichtbaar. Als we een variabele als statische in een functie verklaren, dan is het gedurende die functie alleen zichtbaar. In dit gebruik begint de levensduur van deze statische variabele wanneer een functie-oproep en het zal vernietigen na de uitvoering van die functie. U kunt het volgende voorbeeld zien:

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

hierboven programma geeft ons deze uitvoer:

First Counter Output = 1 
Second Counter Output = 1 

omdat zodra we de functie noemen, zal het de count = 0initialiseren. En terwijl we de counterFunction, vernietigt het de televariabele.

Other episodes