Kiedy umieścić statyczne definicje funkcji w plikach nagłówkowych w C?

Natknąłem się na jakiś kod, który ma dużą statyczną funkcję w pliku nagłówkowym i jestem po prostu ciekaw, kiedy jest/nie jest w porządku, aby to zrobić. Na przykład, jeśli wiele plików .c zawiera nagłówek, dlaczego po prostu nie zdefiniować funkcji non-static i połączyć ją ?

Wszelkie rady lub zasady dotyczące tego, kiedy/kiedy nie umieszczać statycznych definicji funkcji w plikach nagłówkowych w C byłyby mile widziane,

Thanks

Author: horseyguy, 2010-10-18

6 answers

Kilka pomysłów:

  • jednym z możliwych legalnych zastosowań, o którym myślę, jest to, że chcesz udostępnić funkcję bez tworzenia symbolu z zewnętrznym łączem i zanieczyszczania zewnętrznej przestrzeni nazw. (Ale wtedy możesz po prostu użyć niejasnej nazwy z przedrostkiem, takiej jak mylib123__foobar i #define foobar mylib123__foobar w pliku nagłówkowym, więc ten wydaje się trochę niepewny.)
  • chcesz, aby pewne funkcje były dostępne wyłącznie za pośrednictwem pliku nagłówkowego, bez wymogu, aby użytkownik łączył pliki bibliotek / obiektów. Mógłbym zobacz, że jest to prawdziwa motywacja, gdy dostarczamy "bibliotekę", która jest prawie niczym innym jak strukturami danych i kilkoma trywialnymi fragmentami kodu do ich manipulowania. W rzeczywistości, jeśli struktury danych nie są nieprzezroczyste i mają być dostępne bezpośrednio przez aplikację, umieszczenie funkcji do użytku z nimi w tym samym pliku nagłówkowym (w porównaniu z biblioteką) znacznie zmniejsza ryzyko uszkodzenia rzeczy, jeśli/podczas zmiany struktur danych.
  • Być może funkcja jest tylko opakowaniem dla zewnętrznego funkcja i sposób działania wrappera mogą zależeć od opcji czasu kompilacji w wywołującej jednostce kompilacji. Na przykład:

    static int foobar(int x)
    {
        return real_foobar(COMPILETIME_PARAMETER, x);
    }
    

    Można powiedzieć po prostu używać makr, ale co jeśli foobar musi być wywołana za pomocą wskaźnika funkcji dla zamierzonego użycia?

Z tym, że zostało powiedziane...

W rzeczywistości głównym powodem, dla którego ludzie umieszczają funkcje static w plikach nagłówkowych, jest zazwyczaj 10-letnie przekonanie, że poprawi to wydajność, pozwalając na kompilator do wbudowania funkcji lub czegoś takiego. Większość ludzi, którzy to robią, nie wykonała żadnego pomiaru. Ponieważ nowoczesne Kompilatory mogą skompilować cały program jako jednostkę, a to teoretycznie daje o wiele więcej możliwości optymalizacji, a ponieważ jest to wątpliwa Optymalizacja na początek, jestem naprawdę sceptyczny w umieszczaniu funkcji w nagłówkach dla celów wydajności.

Ta krytyka dotyczy szczególnie przykładu "dużych" funkcji statycznych w plikach nagłówkowych. Nie ma prawie żadnej możliwości, aby duża funkcja mogła skorzystać z inliningu, chyba że stała wartość argumentu pozwala kompilatorowi wyeliminować 90% kodu lub coś takiego. (Prawdziwy przykład tego ekstremalnego przypadku można znaleźć w niektórych wariantowych definicjach funkcji/makr inline używanych w libavcodec. :-)

 25
Author: R..,
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-10-18 05:37:31

Z reguły nie należy umieszczać funkcji statycznych w plikach nagłówkowych. W jednorazowym programie prawdopodobnie nic nie zaszkodzi, poza powiększeniem rozmiaru kodu, ponieważ masz nadmiarową kopię w każdym module. W bibliotece współdzielonej może to łatwo powodować błędy, ponieważ teraz część biblioteki jest osadzona w wywoływaczach biblioteki, więc niedopasowanie wersji może się łatwo zdarzyć.

Jeśli masz jakąś strasznie, strasznie czasochłonną funkcję, w której czas spędzony wykonanie wywołania funkcji ma znaczenie, możesz rozważyć umieszczenie go w nagłówku, ale w takim przypadku (a) prawdopodobnie chcesz również zadeklarować go w linii, oraz (b) zrobiłeś już wszystkie inne optymalizacje, które możesz znaleźć.

W skrócie, chyba że wiesz bez cienia wątpliwości, że potrzebujesz swojej statycznej funkcji w pliku nagłówkowym... nie chcesz funkcji statycznej w pliku nagłówkowym; chcesz funkcji niestatycznej w pliku .plik c z nagłówkiem w .h.

 9
Author: Jander,
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-10-18 05:09:34

Z mojego doświadczenia wynika, że generalnie złym pomysłem jest zdefiniowanie funkcji w a .H file, i nigdy nie miałem powodu, aby to zrobić, robiąc to przez przypadek raz spowodował mnie nie koniec bóle głowy.

Chociaż wydaje mi się, że każdy plik zawierający nagłówek miałby własną oddzielną implementację funkcji, która, jeśli funkcja ma statyczne zmienne, może być pożądanym zachowaniem, np. jeśli chcesz/musisz śledzić niektóre informacje oddzielnie dla każdego pliku.

 8
Author: tobyodavies,
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-10-18 05:26:16

Może być również przydatne do definiowania funkcji ze statycznymi buforami pracy, które mają być lokalne dla każdej jednostki tłumaczenia. Szczególnym przykładem jest strtok (). strtok() przechodzi przez bufor po jednym tokenie na każde wywołanie. Jeśli wywołania strtok() są przeplatane z dwóch różnych miejsc (tzn. dwóch różnych jednostek translacyjnych), to wyniki nie są tym, czego się oczekuje/oczekuje. Jeśli każda jednostka tłumaczenia miała własną kopię strtok() i dlatego każda jednostka tłumaczenia miała własne zmienne statyczne strtok (), to tego rodzaju Deptanie stanu wewnętrznego zniknie. Jeśli następuje Deptanie stanu, wtedy oba (zestawy) wywołań są w tej samej jednostce translacyjnej i debugowanie ma pewną pozór local.

(zauważ ,że "poprawnym" rozwiązaniem jest zastąpienie strtok() funkcją bezstanową i uczynienie wywołujących odpowiedzialnymi za przechowywanie informacji o kontekście i stanie, tak samo jak fopen () i friends sprawiają, że wywołujący przechowuje plik dla każdego kontekstu.)

 2
Author: Eric Towers,
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-10-18 05:16:16

Nowoczesne C przyjęło słowo kluczowe inline z C++ do takiego zadania. Ale jeśli twój kompilator tego nie ma (jeszcze?) static w plikach nagłówkowych jest sposobem na emulację tego. inline nie oznacza, że funkcja musi być przypisana do dowolnego wywołującego, ale po prostu, że w finalnym pliku wykonywalnym będzie zwykle co najwyżej jedna kopia. (Technicznie odpowiednie symbole linkera są symbolami "słabymi".) Natomiast, jeśli tylko zadeklarowana static każda jednostka kompilacji zachowa kopię.

Takie podejście posiadanie definicji funkcji w nagłówkach powinno być ograniczone do małych funkcji, które wykonują małe zadania, dla których kompilator może znacznie poprawić kod, jeśli zostanie zoptymalizowany do funkcji wywołującej.

Przy tym należy również uważać na implementację tych funkcji. Możesz przez to przerwać możliwość dołączania deklaracji do C++. Generalnie oba języki zgadzają się tylko (głównie) na Interfejsy, niekoniecznie do implementacji, są subtelne różnice.

 2
Author: Jens Gustedt,
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-10-18 07:01:19

Jeśli funkcja ma powiązania zewnętrzne, powinna być zadeklarowana w a .plik H.

Jeśli funkcja jest statyczna, a zatem nie ma zewnętrznego powiązania, funkcja powinna być zadeklarowana tylko w .plik c, w którym jest zdefiniowany.

Nigdy nie jest w porządku mieć funkcję zdefiniowaną w pliku nagłówkowym.

 -1
Author: Andy Lester,
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-10-18 05:10:32