Co oznacza "statyczny" w C?

Widziałem słowo static używane w różnych miejscach w kodzie C; czy jest to jak statyczna funkcja/klasa w C# (gdzie implementacja jest współdzielona między obiektami)?

Author: jww, 2009-02-21

18 answers

  1. zmienna statyczna wewnątrz funkcji zachowuje swoją wartość między wywołaniami.
  2. statyczna zmienna globalna lub funkcja jest "widziana" tylko w pliku, w którym jest zadeklarowana

(1) jest bardziej obcym tematem, jeśli jesteś nowicjuszem, więc oto przykład:

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

To drukuje:

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

Jest to przydatne w przypadkach, gdy funkcja musi zachować pewien stan między wywołaniami, a nie chcesz używać zmiennych globalnych. Uważaj jednak, ta funkcja powinna być używana bardzo oszczędnie - sprawia, że Twój kod nie jest bezpieczny i trudniejszy do zrozumienia.

(2) jest szeroko stosowany jako funkcja "kontroli dostępu". Jeśli masz .plik C implementujący pewną funkcjonalność, Zwykle wystawia tylko kilka "publicznych" funkcji dla użytkowników. Reszta jego funkcji powinna być wykonana static, aby użytkownik nie miał do nich dostępu. Jest to enkapsulacja, dobra praktyka.

Cytowanie Wikipedia :

W języku programowania C, statyczny jest używany ze zmiennymi globalnymi i funkcje, aby ustawić ich zakres na zawierający plik. W zmiennych lokalnych, static służy do przechowywania zmiennej w pamięci przydzielonej statycznie zamiast automatycznie przydzielanych pamięć. Podczas gdy język nie dyktować realizację albo rodzaj pamięci przydzielanej statycznie pamięć jest zwykle zarezerwowana w danych segment programu przy kompilacji czasu, podczas gdy automatycznie przydzielona pamięć jest zwykle realizowane jako tymczasowy stos połączeń.

Zobacz tutaj i tutaj po więcej szczegółów.

I odpowiadając na drugie pytanie, to nie jest tak jak w C#.

W C++, jednak static jest również używany do definiowania atrybutów klasy (współdzielonych między wszystkimi obiektami tej samej klasy) i metod. W C nie ma klas, więc ta funkcja jest nieistotna.

 1247
Author: Eli Bendersky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-12 14:25:29

Jest jeszcze jedno zastosowanie, które nie jest tu uwzględnione, a jest to część deklaracji typu tablicy jako argument funkcji:

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

W tym kontekście określa, że argumenty przekazywane do tej funkcji muszą być tablicą typu char z co najmniej 10 elementami w niej. Po więcej informacji zobacz moje pytanie tutaj .

 193
Author: dreamlax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:03

Krótka odpowiedź ... To zależy.

  1. Statyczne zdefiniowane zmienne lokalne nie tracą wartości między wywołaniami funkcji. Innymi słowy są zmiennymi globalnymi, ale mają zasięg do lokalnej funkcji, w której są zdefiniowane.

  2. Statyczne zmienne globalne nie są widoczne poza plikiem C, w którym są zdefiniowane.

  3. Funkcje statyczne nie są widoczne poza plikiem C, w którym są zdefiniowane.

 142
Author: cmcginty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-15 14:46:58

Przykład zakresu zmiennych wielu plików

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

Kompilacja :

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

Wyjście :

m()
i = 1
si = 1

m()
i = 2
si = 2

a()
i = 3
si = 1

a()
i = 4
si = 2

Interpretacja

  • istnieją dwie oddzielne zmienne dla si, po jednej dla każdego pliku
  • istnieje jedna wspólna zmienna dla i

Jak zwykle, im mniejszy zakres, tym lepiej, więc zawsze deklaruj zmienne static jeśli możesz.

W programowaniu C, pliki są często używane do reprezentowania "klas", A zmienne static reprezentują prywatne statyczne elementy klasy.

Co mówią o tym standardy

C99 N1256 draft 6.7.1 "storage-class specifiers" mówi, że static jest "storage-class specifier".

6.2.2/3 "powiązania identyfikatorów" mówi static implikuje internal linkage:

Jeśli deklaracja identyfikatora zakresu pliku dla obiektu lub funkcji zawiera statyczny specyfikator klasy storage, identyfikator ma wewnętrzne powiązanie.

I 6.2.2 / 2 mówi, że internal linkage zachowuje się tak jak w naszym przykładzie:

W zbiorze jednostek tłumaczeniowych i bibliotek tworzących cały program, każda deklaracja określonego identyfikatora z powiązaniem zewnętrznym oznacza ten sam obiekt lub funkcję. W ramach jednej jednostki tłumaczeniowej każda deklaracja identyfikatora z wewnętrznym powiązaniem oznacza ten sam obiekt lub funkcję.

Gdzie " jednostka tłumaczenia jest plikiem źródłowym po wstępnym przetworzeniu.

Jak GCC implementuje go dla Elf (Linux)?

Z oprawą STB_LOCAL.

Jeśli skompilujemy:

int i = 0;
static int si = 0;

I demontować tabelę symboli za pomocą:

readelf -s main.o

Wyjście zawiera:

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

Więc wiązanie jest jedyną istotną różnicą między nimi. Value jest tylko ich przesunięciem do .bss sekcji, więc spodziewamy się, że będzie inaczej.

STB_LOCAL jest udokumentowane w specyfikacji ELF na http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :

Symbole lokalne STB_LOCAL nie są widoczne poza plikiem obiektu zawierającym ich definicję. Lokalne symbole o tej samej nazwie mogą istnieć w wielu plikach bez ingerencji ze sobą]}

Co czyni go idealnym wyborem do reprezentowania static.

Zmienne bez statycznych to STB_GLOBAL, A spec mówi:

Gdy link edytor łączy kilka relokowalnych plików obiektowych, nie pozwala na wielokrotne definiowanie symboli STB_GLOBAL o tej samej nazwie.

Który jest spójny z błędami łącza w wielu niestatycznych definicjach.

Jeśli podkręcimy optymalizację za pomocą -O3, symbol si zostanie całkowicie usunięty z tabeli symboli: i tak nie może być używany z zewnątrz. TODO po co w ogóle trzymać statyczne zmienne w tabeli symboli, Gdy nie ma optymalizacji? Czy można je stosować do cokolwiek? Może do debugowania.

Zobacz też

Spróbuj sam

Przykład na github do zabawy.

 47
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 10:51:52

To zależy:

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

Funkcja zwróci 1, 2, 3 itd. --- zmienna nie znajduje się na stosie.

A. C:

static int foo()
{
}

Oznacza to, że ta funkcja ma Zakres tylko w tym pliku. Tak więc a. C i b.C mogą mieć różne foo()s, a foo nie jest wystawione na współdzielone obiekty. Więc jeśli zdefiniowałeś foo w a. c, nie możesz uzyskać do niego dostępu z b.c ani z innych miejsc.

W większości bibliotek C wszystkie funkcje " prywatne "są statyczne, a większość" Publiczna " nie.

 33
Author: Artyom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-28 17:13:57

Ludzie mówią, że 'statyczny' w C ma dwa znaczenia. Oferuję alternatywny sposób oglądania, który nadaje mu jedno znaczenie:

  • Zastosowanie 'static' do elementu wymusza, że element ma dwie właściwości: (a) nie jest widoczny poza bieżącym zakresem; (b) jest trwały.

Powodem, dla którego wydaje się mieć dwa znaczenia, jest to, że w C każdy element, do którego może być zastosowany "statyczny" ma już jedną z tych dwóch właściwości, więc wydaje się tak, jakby szczególne użycie dotyczy tylko drugiego.

Na przykład rozważmy zmienne. Zmienne zadeklarowane poza funkcjami mają już trwałość (w segmencie danych), więc zastosowanie "statycznego" może tylko sprawić, że nie będą widoczne poza bieżącym zakresem (Jednostka kompilacji). Przeciwnie, zmienne zadeklarowane wewnątrz funkcji już nie mają widoczności poza bieżącym zakresem (funkcją), więc stosowanie "statycznych" może tylko sprawić, że będą trwałe.

Zastosowanie 'statycznego' do funkcji jest tylko podobnie jak stosowanie go do zmiennych globalnych-kod jest koniecznie trwały (przynajmniej w obrębie języka), więc tylko widoczność może być zmieniona.

UWAGA: te komentarze odnoszą się tylko do C. W C++ stosowanie' statycznych ' metod klasowych naprawdę nadaje słowu kluczowemu inne znaczenie. Podobnie dla rozszerzenia tablicy C99.

 18
Author: PMar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 13:47:26

static oznacza różne rzeczy w różnych kontekstach.

  1. Możesz zadeklarować zmienną statyczną w funkcji C. Ta zmienna jest widoczna tylko w funkcji, ale zachowuje się jak globalna, ponieważ jest inicjalizowana tylko raz i zachowuje swoją wartość. W tym przykładzie za każdym razem, gdy wywołasz foo(), wyświetli rosnącą liczbę. Zmienna statyczna jest inicjalizowana tylko raz.

    void foo ()
    {
    static int i = 0;
    printf("%d", i); i++
    }
    
  2. Innym zastosowaniem statycznych jest implementacja funkcji lub globalne zmienna w a .plik c, ale nie chce, aby jego symbol był widoczny poza .obj wygenerowanym przez plik. np.

    static void foo() { ... }
    
 12
Author: m-sharp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-17 13:43:25

Z Wikipedii:

w języku programowania C, static jest używany z globalnymi zmiennymi i funkcjami, aby ustawić ich zakres na plik zawierający. W zmiennych lokalnych zmienna statyczna jest używana do przechowywania zmiennej w statycznie przydzielonej pamięci zamiast automatycznie przydzielonej pamięci. Podczas gdy język nie dyktuje implementacji żadnego z typów pamięci, statycznie przydzielana pamięć jest zwykle zarezerwowana w segmencie danych programu podczas kompilacji czasu, podczas gdy automatycznie przydzielana pamięć jest normalnie zaimplementowana jako tymczasowy stos wywołań.

 11
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-21 06:52:18

Nienawidzę odpowiadać na Stare pytanie, ale chyba nikt nie wspomniał, jak k & r wyjaśnia to w sekcji A4.1 "języka programowania C".

W skrócie słowo static używane jest z dwoma znaczeniami:

  1. statyczna jest jedną z dwóch klas pamięci (druga to automatyczny). Obiekt statyczny zachowuje swoją wartość między wywołaniami. Obiekty zadeklarowane poza wszystkimi blokami są zawsze statyczne i nie mogą być wykonane automatycznie.
  2. Ale kiedy static słowo kluczowe (duży nacisk na to, że jest używany w kod jako słowo kluczowe) jest używany z deklaracją, daje temu obiektowi wewnętrzne powiązanie, więc może być używany tylko w tej jednostce tłumaczenia. Ale jeśli słowo kluczowe jest użyte w funkcji, to zmienia klasę przechowywania obiektu (obiekt i tak będzie widoczny tylko w tej funkcji). Przeciwieństwem statycznego jest słowo kluczowe extern, które daje obiektowi zewnętrzne powiązanie.
Peter Van Der Linden podaje te dwa znaczenia w "Expert Programowanie C": {]}
  • wewnątrz funkcji zachowuje jej wartość między wywołaniami.
  • na poziomie funkcji, widoczna tylko w tym pliku.
 6
Author: nobism,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-12 03:34:46

Jeśli zadeklarujesz zmienną w funkcji statycznej, jej wartość nie będzie przechowywana na stosie wywołań funkcji i nadal będzie dostępna po ponownym wywołaniu funkcji.

Jeśli zadeklarujesz statyczną zmienną globalną, jej zakres będzie ograniczony do pliku, w którym ją zadeklarowałeś. Jest to nieco bezpieczniejsze niż zwykły globalny, który można czytać i modyfikować w całym programie.

 5
Author: Sam Hoice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-21 06:52:48

W C, statyczny ma dwa znaczenia, w zależności od zakresu jego zastosowania. W obszarze globalnym, gdy obiekt jest zadeklarowany na poziomie pliku, oznacza to, że obiekt ten jest widoczny tylko w tym pliku.

W każdym innym zakresie deklaruje obiekt, który zachowa swoją wartość między różnymi czasami, w których dany zakres jest wprowadzany. Na przykład, jeśli int jest delcared w ramach procedury:

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

   i++;
}

Wartość " i " jest inicjalizowana na zero przy pierwszym wywołaniu procedury, a wartość jest zatrzymywana przy każdym wywołaniu procedury. jeśli' i ' zostałoby wydrukowane, otrzymywałoby sekwencję 0, 1, 2, 3,...

 5
Author: schot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-25 13:07:06

Jeśli zadeklarujesz to w mytest.plik c:

static int my_variable;

Wtedy ta zmienna może być widoczna tylko z tego pliku. Zmiennej nie można wyeksportować nigdzie indziej.

Jeśli zadeklarujesz wewnątrz funkcji, wartość zmiennej zachowa swoją wartość za każdym razem, gdy funkcja zostanie wywołana.

Statyczna funkcja nie może być eksportowana spoza pliku. Więc w *.plik c, ukrywasz funkcje i zmienne, jeśli zadeklarujesz je statyczne.

 4
Author: ant2009,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-18 16:49:02

Ważne jest, aby zauważyć, że statyczne zmienne w funkcjach są inicjalizowane przy pierwszym wejściu do tej funkcji i utrzymują się nawet po zakończeniu ich wywołania; w przypadku funkcji rekurencyjnych statyczna zmienna jest inicjalizowana tylko raz i utrzymuje się przez wszystkie wywołania rekurencyjne, a nawet po zakończeniu wywołania funkcji.

Jeśli zmienna została utworzona poza funkcją, to znaczy, że programista może używać zmiennej tylko w plik źródłowy zmiennej został zadeklarowany.

 3
Author: Starhowl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-01 06:30:15

Należy również pamiętać, że static może być używany na 4 różne sposoby.

to create permanent storage for local variables in a function.
to specify internal linkage.
to declare member functions that act like non-member functions.
to create a single copy of a data member.
 2
Author: amrx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-06 23:03:28

Zmienna statyczna jest specjalną zmienną, której można użyć w funkcji i zapisuje dane między wywołaniami, a nie usuwa ich między wywołaniami. Na przykład:

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

Wyjście:

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

 2
Author: Yagel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-28 17:16:23

Zmienne statyczne w C mają czas życia programu.

Jeśli są zdefiniowane w funkcji, mają zasięg lokalny, tzn. mogą być dostępne tylko wewnątrz tych funkcji. Wartość zmiennych statycznych jest zachowywana pomiędzy wywołaniami funkcji.

Na przykład:

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

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

W powyższym programie, var jest przechowywany w segmencie danych. Jego żywotność to cały program C.

Po wywołaniu funkcji 1, var staje się 2. Po wywołaniu funkcji 2, var staje się 3.

Wartość var nie jest niszczona pomiędzy wywołaniami funkcji.

Gdyby var miała zmienną niestatyczną i lokalną, byłaby przechowywana w segmencie stosu w programie C. Ponieważ ramka stosu funkcji jest niszczona po jej powrocie, wartość var jest również niszczona.

Zainicjalizowane zmienne statyczne są przechowywane w segmencie danych programu C, podczas gdy niezinicjalizowane są przechowywane w segmencie BSS.

Kolejna informacja o static: jeśli zmienna jest globalna i statyczna, ma czas życia programu C, ale ma zakres plików. Jest widoczny tylko w tym pliku.

Aby spróbować:

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

Teraz spróbuj połączyć je za pomocą:

gcc -o output file1.o file2.o

Dałoby to błąd linkera, ponieważ X ma zakres pliku file1.c i linker nie byłby w stanie rozwiązać odniesienia do zmiennej x używanej w file2.c.

Bibliografia:

  1. http://en.wikipedia.org/wiki/Translation_unit_ (programowanie)
  2. http://en.wikipedia.org/wiki/Call_stack
 2
Author: Sahil Manchanda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-28 17:21:46

Wartość zmiennej statycznej utrzymuje się pomiędzy różnymi wywołaniami funkcji, a jej zakres jest ograniczony do bloku lokalnego statyczna zmienna zawsze inicjalizuje się wartością 0

 1
Author: Jonathon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-23 05:48:32

Są 2 przypadki:

(1) zmienne lokalne zadeklarowane static: przydzielone w segmencie danych zamiast stosu. Jego wartość zachowuje się po ponownym wywołaniu funkcji.

(2) globalne zmienne lub funkcje zadeklarowane static: niewidoczne poza jednostką kompilacji(tzn. są lokalnymi symbolami w tabeli symboli podczas łączenia).

 1
Author: Jonny Kong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-03 13:01:49