Co to jest funkcja "statyczna"?

Pytanie dotyczyło prostych C funkcji, a nie c++ static metody, jak wyjaśniono w komentarzach.

Ok, rozumiem co to jest static zmienna, ale co to jest static funkcja?

I dlaczego jeśli zadeklaruję funkcję, powiedzmy void print_matrix, powiedzmy a.c (Bez a.h) I include "a.c" - otrzymuję "print_matrix@@....) already defined in a.obj", ale jeśli zadeklaruję ją jako static void print_matrix, to kompiluje?

UPDATE tylko dla wyjaśnienia - wiem, że w tym {[9] } jest źle, jak wielu z Was na to wskazywało. Robię to tylko, aby tymczasowo wyczyścić miejsce w main.c, dopóki nie mam lepszego pomysłu, jak pogrupować wszystkie te funkcje w odpowiednie pliki .h i .c. Tylko tymczasowe, szybkie rozwiązanie.

Author: Alex, 2009-02-17

11 answers

static funkcje są funkcjami, które są widoczne tylko dla innych funkcji w tym samym pliku (dokładniej ta sama jednostka tłumaczenie).

EDIT: dla tych, którzy myśleli, że autor pytań miał na myśli 'metodę klasową': jako pytanie jest oznaczone C ma na myśli zwykłą starą funkcję C. For (C++ / Java/...) metody klasy, static oznacza, że ta metoda może być wywołana na samej klasie, Żadna instancja tej klasy nie jest konieczna.

 580
Author: Johannes Weiss,
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
2015-04-28 20:29:22

Istnieje duża różnica między funkcjami statycznymi w C i funkcjami statycznymi w C++. W języku C funkcja statyczna nie jest widoczna poza jednostką translacji, która jest plikiem obiektowym, do którego jest kompilowana. Innymi słowy, wykonanie funkcji statycznej ogranicza jej zakres. Możesz myśleć o funkcji statycznej jako o "prywatnej" jej*.plik c (choć nie jest to do końca poprawne).

W C++, "static" może również odnosić się do funkcji Członkowskich i członków danych klas. Dane statyczne member jest również nazywany "zmienną klasy", podczas gdy niestatyczny element danych jest "zmienną instancji". To jest terminologia Smalltalk. Oznacza to, że istnieje tylko jedna kopia statycznego elementu danych współdzielona przez wszystkie obiekty klasy, podczas gdy każdy obiekt ma swoją własną kopię niestatycznego elementu danych. Tak więc statyczny element danych jest zasadniczo zmienną globalną, która jest członkiem klasy.

Non - static funkcje Członkowskie mogą uzyskać dostęp do wszystkich danych klasy: static i non-static. Static funkcje Członkowskie mogą działać tylko na statycznych członach danych.

Jednym ze sposobów myślenia jest to, że w C++ statyczne pręty danych i statyczne funkcje prętowe nie należą do żadnego obiektu, ale do całej klasy.

 177
Author: Dima,
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-04-04 11:13:40

Istnieją dwa zastosowania słowa kluczowego static, jeśli chodzi o funkcje w C++.

Pierwszy polega na oznaczeniu funkcji jako posiadającej wewnętrzne powiązanie, więc nie można jej odwoływać się do innych jednostek translacyjnych. To użycie jest przestarzałe w C++. Do tego użycia preferowane są nienazwane przestrzenie nazw.

// inside some .cpp file:

static void foo();    // old "C" way of having internal linkage

// C++ way:
namespace
{
   void this_function_has_internal_linkage()
   {
      // ...
   }
}

Drugie użycie jest w kontekście klasy. Jeśli klasa ma statyczną funkcję członka, to znaczy, że funkcja jest członkiem klasy (i ma zwykły dostęp do innych członków), ale nie musi być wywoływany przez konkretny obiekt. Innymi słowy, wewnątrz tej funkcji nie ma "tego" wskaźnika.

 69
Author: Brian Neal,
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-17 21:08:30

Minimal runnable multi-file example

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
*/
/*void f() { puts("a f"); }*/

/* OK: only declared, not defined. Will use the one in main. */
void f(void);

/* OK: only visible to this file. */
static void sf() { puts("a sf"); }

void a() {
    f();
    sf();
}

Main.c:

#include <stdio.h>

void a(void);        

void f() { puts("main f"); }

static void sf() { puts("main sf"); }

void m() {
    f();
    sf();
}

int main() {
    m();
    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 :

main f
main sf
main f
a sf

Interpretacja

  • istnieją dwie oddzielne funkcje sf, po jednej dla każdego pliku
  • istnieje jedna wspólna funkcja f

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

W programowaniu C, pliki są często używane do reprezentowania "klas", a static Funkcje reprezentują" prywatne " metody klasy.

Powszechnym wzorcem C jest przekazanie struktury this jako pierwszego argumentu "method", czyli tego, co C++ robi pod maską.

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" identyfikatory " 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 linkiem zewnętrznym oznacza ten sam obiekt lub funkcja. 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 f() { return 0; }
static int sf() { return 0; }

I demontować tabelę symboli za pomocą:

readelf -s main.o

Wyjście zawiera:

Num:    Value          Size Type    Bind   Vis      Ndx Name
  5: 000000000000000b    11 FUNC    LOCAL  DEFAULT    1 sf
  9: 0000000000000000    11 FUNC    GLOBAL DEFAULT    1 f

Więc wiązanie jest jedynym znacząca różnica 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 doskonały wybór do reprezentowania static.

Funkcje bez statyki to STB_GLOBAL, A spec mówi:

Gdy 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 sf zostanie całkowicie usunięty z tabeli symboli: nie może być używane z zewnątrz i tak. TODO po co w ogóle trzymać statyczne funkcje w tabeli symboli, Gdy nie ma optymalizacji? Czy można ich używać do czegokolwiek?

Zobacz też

Spróbuj. siebie

Przykład na GitHub do zabawy.

 34
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-25 11:32:51

Poniższy tekst dotyczy zwykłych funkcji C - w klasie C++ modyfikator 'static' ma inne znaczenie.

Jeśli masz tylko jeden plik, ten modyfikator nie robi żadnej różnicy. Różnica pojawia się w większych projektach z wieloma plikami:

W C, każdy "moduł" (kombinacja próbki.c i próbka.h) jest kompilowany niezależnie, a następnie każdy z tych skompilowanych plików obiektowych (przykład.o) są połączone razem z plikiem wykonywalnym przez łącznik.

Let ' s say you miej kilka plików, które dołączasz do głównego pliku, a dwa z nich mają funkcję, która jest używana tylko wewnętrznie dla wygody o nazwie add(int a, b) - kompilator łatwo utworzy pliki obiektowe dla tych dwóch modułów, ale linker wyrzuci błąd, ponieważ znajdzie dwie funkcje o tej samej nazwie i nie wie, której z nich powinien użyć (nawet jeśli nie ma nic do linkowania, ponieważ nie są one używane gdzie indziej, ale w jego własnym pliku).

Dlatego tworzysz tę funkcję, która jest używany tylko wewnętrzny, funkcja statyczna. W tym przypadku kompilator nie tworzy typowej flagi"you can link this thing" dla linkera, tak że linker nie widzi tej funkcji i nie wygeneruje błędu.

 18
Author: dersimn,
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-04-25 22:49:07

Po pierwsze: generalnie nie jest dobrym pomysłem dołączanie pliku .cpp do innego pliku - prowadzi to do takich problemów :-) normalnym sposobem jest tworzenie oddzielnych jednostek kompilacji i dodawanie pliku nagłówkowego dla dołączonego pliku.

Po Drugie:

C++ ma tu trochę mylącej terminologii - nie wiedziałem o tym, dopóki nie zwróciłem uwagi w komentarzach.

A) static functions - dziedziczone z C, i o czym tu mówisz. Poza żadną klasą. Statyczna funkcja oznacza, że nie jest widoczny poza bieżącą jednostką kompilacji - więc w Twoim przypadku.obj ma kopię, a twój drugi kod ma niezależną kopię. (Wypełnianie finalnego pliku wykonywalnego wieloma kopiami kodu).

B) static member function - jaka orientacja obiektu określa statyczną metodę . Mieszka w klasie. Wywołujesz to za pomocą klasy, a nie przez instancję obiektu.

Te dwie różne definicje funkcji statycznych są zupełnie inne. Bądź ostrożny-tutaj być smoki.

 14
Author: Douglas Leeder,
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-06-24 06:06:46

Statyczne definicje funkcji oznaczą Ten symbol jako wewnętrzny. Nie będzie więc widoczny dla linkowania z zewnątrz, a tylko dla funkcji w tej samej jednostce kompilacji, Zwykle tego samego pliku.

 13
Author: raimue,
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-17 18:28:44

Statyczna funkcja to taka, która może być wywołana na samej klasie, w przeciwieństwie do instancji klasy.

Na przykład nie-statyczne byłoby:

Person* tom = new Person();
tom->setName("Tom");

Ta metoda działa na instancji klasy, a nie na samej klasie. Jednak możesz mieć statyczną metodę, która może działać bez wystąpienia. Jest to czasami używane w wzorze fabrycznym:

Person* tom = Person::createNewPerson();
 8
Author: Parrots,
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-17 18:31:56

Minor nit: funkcje statyczne są widoczne dla jednostki translacyjnej, która dla większości praktycznych przypadków jest plikiem, w którym zdefiniowana jest funkcja. Błąd, który otrzymujesz, jest powszechnie określany jako naruszenie zasady jednej definicji.

Standard prawdopodobnie mówi coś w stylu:

" każdy program powinien zawierać dokładnie jedną definicję każdego noninline funkcji lub obiektu, który jest używany w tym programie; brak diagnostyki wymagane."

That is the C way of patrząc na funkcje statyczne. Jest to jednak przestarzałe w C++.

W C++ dodatkowo Można zadeklarować funkcje składowe statyczne. Są to głównie metafunkcje, tzn. nie opisują/modyfikują zachowania / stanu danego obiektu, ale działają na całą klasę. Oznacza to również, że nie trzeba tworzyć obiektu, aby wywołać statyczną funkcję członka. Co więcej, oznacza to również, że dostęp do statycznych zmiennych członkowskich uzyskujesz tylko z poziomu takiej funkcji.

Dodałbym do papugi przykład wzór Singletona, który jest oparty na tego rodzaju statycznej funkcji składowej, aby uzyskać / używać pojedynczego obiektu przez cały okres życia programu.

 6
Author: dirkgently,
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-17 18:50:57

Odpowiedź na funkcję statyczną zależy od języka:

1) w językach bez UPS, takich jak C, oznacza to, że funkcja jest dostępna tylko w pliku, w którym została zdefiniowana.

2) w językach z UPS, takich jak C++, oznacza to, że funkcja może być wywołana bezpośrednio na klasie bez tworzenia jej instancji.

 6
Author: user2410022,
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-03-06 13:31:35

Dla funkcji statycznej w "c" kompilator nie utworzy swoich wewnętrznych zmiennych na stosie, więc statyczne wywołanie funkcji jest szybsze, a w konsekwencji nie można używać inicjalizatorów takich jak: char c= 'a'.

 -4
Author: Alex,
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-11-05 19:17:48