Pytanie dotyczyło zwykłego do funkcje, a nie c ++ static
metody, jak wyjaśniono w komentarzach.
Rozumiem, czym jest static
zmienna, ale czym jest static
funkcja?
I dlaczego jest tak, że jeśli zadeklaruję funkcję, powiedzmy void print_matrix
, powiedzmy a.c
(BEZ a.h
) i dołączę "a.c"
- rozumiem "print_matrix@@....) already defined in a.obj"
, ALE jeśli zadeklaruję ją tak, jak się static void print_matrix
wtedy kompiluje?
AKTUALIZACJA Żeby wszystko wyjaśnić - wiem, że włączenie .c
jest złe, jak wielu z was zauważyło. Po prostu robię to, aby tymczasowo zwolnić miejsce, main.c
dopóki nie będę miał lepszego pojęcia, jak zgrupować wszystkie te funkcje w odpowiednie .h
i .c
pliki. Tylko tymczasowe, szybkie rozwiązanie.
źródło
Istnieje duża różnica między funkcjami statycznymi w C a statycznymi funkcjami członka w C ++. W C funkcja statyczna nie jest widoczna poza jednostką tłumaczącą, która jest plikiem obiektowym, w którym jest kompilowana. Innymi słowy, uczynienie funkcji statyczną ogranicza jej zasięg. Możesz uznać funkcję statyczną za „prywatną” dla jej pliku * .c (chociaż nie jest to ściśle poprawne).
W C ++ „statyczny” może również odnosić się do funkcji składowych i członków danych klas. Statyczny element danych jest również nazywany „zmienną klasy”, podczas gdy niestatyczny element danych jest „zmienną instancji”. To terminologia Smalltalk. Oznacza to, że istnieje tylko jedna kopia statycznego elementu danych współużytkowanego przez wszystkie obiekty klasy, podczas gdy każdy obiekt ma własną kopię niestatycznego elementu danych. Zatem element danych statycznych jest zasadniczo zmienną globalną, która jest członkiem klasy.
Niestatyczne funkcje składowe mogą uzyskać dostęp do wszystkich elementów danych klasy: statycznych i niestatycznych. Funkcje elementów statycznych mogą działać tylko na elementach danych statycznych.
Jednym ze sposobów myślenia o tym jest to, że w C ++ elementy danych statycznych i funkcje elementów statycznych nie należą do żadnego obiektu, ale do całej klasy.
źródło
Istnieją dwa zastosowania słowa kluczowego static, jeśli chodzi o funkcje w C ++.
Pierwszym jest oznaczenie funkcji jako wewnętrznej powiązania, aby nie można było odwoływać się do niej w innych jednostkach tłumaczeniowych. To użycie jest przestarzałe w C ++. Dla tego zastosowania preferowane są nienazwane przestrzenie nazw.
Drugie użycie jest w kontekście klasy. Jeśli klasa ma statyczną funkcję członka, oznacza to, że funkcja jest członkiem klasy (i ma zwykły dostęp do innych członków), ale nie musi być wywoływana przez określony obiekt. Innymi słowy, wewnątrz tej funkcji nie ma wskaźnika „ten”.
źródło
Przykład minimalnego zakresu wielu plików do uruchomienia
Tutaj ilustruję, jak
static
wpływa na zakres definicji funkcji w wielu plikach.ac
main.c
GitHub w górę .
Skompiluj i uruchom:
Wynik:
Interpretacja
sf
, po jednej dla każdego plikuf
Jak zwykle, im mniejszy zakres, tym lepiej, więc zawsze deklaruj funkcje,
static
jeśli możesz.W programowaniu C pliki są często używane do reprezentowania „klas”, a
static
funkcje reprezentują „prywatne” metody klasy.Powszechnym wzorcem C jest przekazywanie
this
struktury jako pierwszego argumentu „metody”, który jest w zasadzie tym, co C ++ robi pod maską.Co mówią o tym standardy
C99 N1256 wersja robocza 6.7.1 „ Specyfikatory klasy pamięci” mówią, że
static
jest to „specyfikator klasy pamięci”.6.2.2 / 3 „Powiązania identyfikatorów” mówi
static
zakładainternal linkage
:a 6.2.2 / 2 mówi, że
internal linkage
zachowuje się jak w naszym przykładzie:gdzie „jednostka tłumacząca” jest plikiem źródłowym po wstępnym przetwarzaniu.
Jak GCC implementuje to dla ELF (Linux)?
Z
STB_LOCAL
wiązaniem.Jeśli skompilujemy:
i zdemontować tabelę symboli za pomocą:
wyjście zawiera:
więc wiązanie jest jedyną znaczącą różnicą między nimi.
Value
jest tylko ich przesunięciem do.bss
sekcji, więc spodziewamy się, że będzie się różnić.STB_LOCAL
jest udokumentowany w specyfikacji ELF pod adresem http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :co czyni go idealnym wyborem do reprezentowania
static
.Funkcje bez statyczne są
STB_GLOBAL
, a specyfikacja mówi:co jest spójne z błędami łącza w wielu definicjach niestatycznych.
Jeśli zwiększymy optymalizację za pomocą
-O3
,sf
symbol zostanie całkowicie usunięty z tabeli symboli: i tak nie można go używać z zewnątrz. TODO po co w ogóle utrzymywać funkcje statyczne na tablicy symboli, gdy nie ma optymalizacji? Czy można ich używać do czegokolwiek?Zobacz też
extern
jest odwrotnościąstatic
i funkcje są jużextern
domyślnie: Jak korzystać z extern do udostępniania zmiennych między plikami źródłowymi?Anonimowe przestrzenie nazw C ++
W C ++ możesz użyć anonimowych przestrzeni nazw zamiast statycznych, co daje podobny efekt, ale dodatkowo ukrywa definicje typów: Bezimienne / anonimowe przestrzenie nazw vs. funkcje statyczne
źródło
void f() { puts("sf"); }
(tj. dwie definicjef()
) powoduje niezdefiniowane zachowanie bez wymaganej diagnostyki. Problem z jakością linkera polega na tym, że faktycznie pojawia się komunikat o błędzie.Poniższe informacje dotyczą zwykłych funkcji C - w klasie C ++ modyfikator „static” ma inne znaczenie.
Jeśli masz tylko jeden plik, ten modyfikator nie ma absolutnie żadnej różnicy. Różnica polega na większych projektach z wieloma plikami:
W C każdy „moduł” (kombinacja sample.c i sample.h) jest kompilowany niezależnie, a następnie każdy z tych skompilowanych plików obiektowych (sample.o) jest łączony razem z plikiem wykonywalnym przez linker.
Załóżmy, że masz kilka plików, które dołączasz do pliku głównego, a dwa z nich mają funkcję używaną tylko wewnętrznie dla wygody, nazywaną
add(int a, b)
- kompilator łatwo utworzy pliki obiektowe dla tych dwóch modułów, ale linker zgłasza błąd, ponieważ znajduje dwie funkcje o tej samej nazwie i nie wie, z której powinien skorzystać (nawet jeśli nie ma nic do połączenia, ponieważ nie są one używane gdzie indziej, ale we własnym pliku).Właśnie dlatego czynisz tę funkcję, która jest używana tylko wewnętrznie, funkcją statyczną. W takim przypadku kompilator nie tworzy typowej flagi „można połączyć to coś” dla linkera, dzięki czemu linker nie widzi tej funkcji i nie generuje błędu.
źródło
Po pierwsze: umieszczenie
.cpp
pliku w innym pliku jest na ogół złym pomysłem - prowadzi to do takich problemów :-) Normalnym sposobem jest utworzenie osobnych jednostek kompilacji i dodanie pliku nagłówka dla dołączonego pliku.Po drugie:
C ++ ma tutaj mylącą terminologię - nie wiedziałem o tym, dopóki nie wskazałem tego w komentarzach.
a)
static functions
- odziedziczone po C i o czym tu mówisz. Poza każdą klasą. Statyczna funkcja oznacza, że nie są widoczne na zewnątrz obecna jednostka kompilacji - tak w twoim przypadku a.obj ma kopię a drugi kod ma niezależną kopię. (Nadęty końcowy plik wykonywalny z wieloma kopiami kodu).b)
static member function
- co Object Orientation nazywa metodą statyczną . Mieszka w klasie. Nazywasz to klasą, a nie instancją obiektu.Te dwie różne definicje funkcji statycznych są całkowicie różne. Uważaj - tu będą smoki.
źródło
definicje funkcji statycznych oznaczą ten symbol jako wewnętrzny. Nie będzie więc widoczny do łączenia z zewnątrz, a jedynie do funkcji w tej samej jednostce kompilacji, zwykle w tym samym pliku.
źródło
Funkcja statyczna to taka, którą można wywołać w samej klasie, w przeciwieństwie do instancji klasy.
Na przykład niestatyczna byłaby:
Ta metoda działa na instancji klasy, a nie na samej klasie. Możesz jednak mieć metodę statyczną, która może działać bez instancji. Jest to czasami używane we wzorcu fabrycznym:
źródło
Drobna nit: funkcje statyczne są widoczne dla jednostki tłumaczeniowej, która w większości praktycznych przypadków jest plikiem, w którym funkcja jest zdefiniowana. Otrzymany błąd jest powszechnie określany jako naruszenie reguły One Definition.
Standard prawdopodobnie mówi coś takiego:
Jest to sposób patrzenia na funkcje statyczne w języku C. Jest to jednak przestarzałe w C ++.
Dodatkowo w C ++ możesz zadeklarować funkcje składowe jako statyczne. Są to głównie metafunkcje, tzn. Nie opisują / nie modyfikują zachowania / stanu określonego obiektu, ale działają na całą klasę. Oznacza to również, że nie trzeba tworzyć obiektu, aby wywoływać funkcję członka statycznego. Ponadto oznacza to również, że dostęp do statycznych zmiennych składowych uzyskuje się tylko z poziomu takiej funkcji.
Dodałbym do przykładu Parrota wzorzec Singleton, który jest oparty na tego rodzaju statycznej funkcji składowej, aby uzyskać / użyć jednego obiektu przez cały czas istnienia programu.
źródło
Odpowiedź na funkcję statyczną zależy od języka:
1) W językach bez OOPS, takich jak C, oznacza to, że funkcja jest dostępna tylko w pliku, w którym jest zdefiniowana.
2) W językach z OOPS, takich jak C ++, oznacza to, że funkcję można wywołać bezpośrednio w klasie bez tworzenia jej instancji.
źródło
static
ma również zakres pliku, podobnie jak w C.Ponieważ funkcja statyczna jest widoczna tylko w tym pliku. Właściwie kompilator może przeprowadzić dla ciebie optymalizację , jeśli zadeklarujesz „statyczny” dla jakiejś funkcji.
Oto prosty przykład.
main.c
I kompiluj z
Zobaczysz, że to się nie udało. Ponieważ nawet nie implementujesz funkcji ghost ().
Ale co, jeśli użyjemy następującego polecenia.
To sukces , a ten program można uruchomić normalnie.
Dlaczego? Istnieją 3 kluczowe punkty.
Tylko jeśli te 3 warunki są spełnione, możesz przejść kompilację. Z powodu tej „statycznej” deklaracji kompilator może potwierdzić, że test () NIGDY nie zostanie wywołany w innym pliku. Twój kompilator może usunąć test () podczas kompilacji. Ponieważ nie potrzebujemy test (), nie ma znaczenia, czy ghost () jest zdefiniowany czy wdrożony.
źródło
Zacznijmy od początku.
Wszystko opiera się na rzeczy zwanej „łączeniem”:
Jeśli funkcja jest zdefiniowana bez specyfikatora klasy pamięci, funkcja ma
extern
domyślnie wszystkie powiązania:Oznacza to, że - jeśli twój program zawiera kilka jednostek tłumaczeniowych / plików źródłowych (
.c
lub.cpp
) - funkcja jest widoczna we wszystkich jednostkach tłumaczeniowych / plikach źródłowych, które posiada Twój program.W niektórych przypadkach może to stanowić problem. Co jeśli chcesz użyć np. Dwóch różnych funkcji (definicji), ale o tej samej nazwie funkcji w dwóch różnych kontekstach (w rzeczywistości w kontekście pliku).
W C i C ++
static
kwalifikator klasy pamięci zastosowany do funkcji w zakresie pliku (nie jest statyczną funkcją składową klasy w C ++ lub funkcją w innym bloku) teraz pomaga i oznacza, że odpowiednia funkcja jest widoczna tylko wewnątrz jednostka tłumacząca / plik źródłowy, w którym została zdefiniowana, a nie w innych jednostkach TLU / plikach.Zatem
static
funkcja A ma sens, iff:Twój program zawiera kilka jednostek tłumaczeniowych / plików źródłowych (
.c
lub.cpp
).i
Chcesz ograniczyć zakres funkcji do pliku, w którym zdefiniowano określoną funkcję.
Jeśli oba te wymagania nie są zgodne, nie musisz zawracać sobie głowy kwalifikowaniem funkcji jako
static
.Notatki dodatkowe:
Jak już wspomniano,
static
funkcja A nie ma absolutnie żadnej różnicy między C i C ++, ponieważ jest to funkcja C ++ odziedziczona po C.Nie ma znaczenia, że w społeczności C ++ toczy się bolesna debata na temat deprecjacji kwalifikujących się funkcji, ponieważ
static
w porównaniu z użyciem zamiast nich nienazwanych przestrzeni nazw , najpierw zainicjowanych przez niewłaściwie umieszczony akapit w standardzie C ++ 03, deklarując użycie funkcje statyczne jako przestarzałe, które wkrótce zostały poprawione przez sam komitet i usunięte w C ++ 11.To było przedmiotem różnych pytań SO:
Nienazwane / anonimowe przestrzenie nazw a funkcje statyczne
Przewaga nienazwanej przestrzeni nazw nad statyczną?
Dlaczego nienazwana przestrzeń nazw jest „lepszą” alternatywą od statycznej?
Wycofanie statycznego słowa kluczowego ... już nie?
W rzeczywistości nie jest jeszcze przestarzałe w stosunku do standardu C ++. Dlatego korzystanie z
static
funkcji jest nadal uzasadnione. Nawet jeśli nienazwane przestrzenie nazw mają zalety, dyskusja na temat używania lub niestosowania funkcji statycznych w C ++ zależy od jednego umysłu (opartego na opiniach) i nie nadaje się dla tej witryny.źródło