Jaka jest różnica między funkcją „static” a „static inline”?

123

IMO obie sprawiają, że funkcja obejmuje tylko zakres jednostki tłumaczeniowej.

Jaka jest różnica między funkcją „static” a „static inline”?

Dlaczego należy inlineumieścić w pliku nagłówkowym, a nie w .cpliku?

nowy_perl
źródło

Odpowiedzi:

108

inlineinstruuje kompilator, aby spróbował osadzić zawartość funkcji w kodzie wywołującym zamiast wykonywania rzeczywistego wywołania.

W przypadku małych funkcji, które są często wywoływane, mogą mieć duży wpływ na wydajność.

Jest to jednak tylko „wskazówka” i kompilator może ją zignorować, a większość kompilatorów będzie próbować wstawiać ją w tekście, nawet jeśli słowo kluczowe nie jest używane, w ramach optymalizacji, o ile jest to możliwe.

na przykład:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Ta ścisła pętla wykona wywołanie funkcji w każdej iteracji, a zawartość funkcji jest w rzeczywistości znacznie mniejsza niż kod, który kompilator musi umieścić, aby wykonać wywołanie. inlinezasadniczo poinstruuje kompilator, aby przekonwertował powyższy kod na odpowiednik:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Pomijanie rzeczywistego wywołania funkcji i powrotu

Oczywiście jest to przykład, który ma pokazać, a nie prawdziwy fragment kodu.

staticodnosi się do zakresu. W C oznacza to, że funkcja / zmienna może być używana tylko w tej samej jednostce tłumaczeniowej.

littleadv
źródło
4
Nie, staticdotyczy zakresu. W C oznacza to, że funkcja / zmienna może być używana tylko w tej samej jednostce tłumaczeniowej.
littleadv
8
Należy również zauważyć, że kod zadeklarowany jako inline należy do nagłówka, gdzie normalny (nie szablonowy) kod źródłowy nie może zostać umieszczony w nagłówkach bez powodowania wielu błędów redefinicji. Więc nawet jeśli deklarujesz coś w tekście, nawet jeśli kompilator zdecyduje się tego nie robić, nadal istnieje standardowa
wymóg
13
@VoidStar Właściwie static(z lub bez inline) może być w nagłówku doskonale, nie widzę powodu, dlaczego nie. Szablony są dla C ++, to pytanie dotyczy C.
littleadv
2
@littleadv: głównym powodem umieszczania definicji funkcji w plikach nagłówkowych jest uczynienie ich nieliniowymi, więc wyraźne oznaczenie ich inlinejest dobrym stylem, imo
Christoph
10
Właściwie inlinenie instruuje kompilatora, aby podejmował jakiekolwiek próby wstawiania. Pozwala tylko programiście na włączenie treści funkcji do wielu jednostek tłumaczeniowych bez naruszenia ODR. Efektem ubocznym tego jest to, że umożliwia kompilatorowi, gdy mógłby to zrobić, w rzeczywistości.
Rusłan
96

Domyślnie definicja wbudowana obowiązuje tylko w bieżącej jednostce tłumaczeniowej.

Jeśli klasa pamięci to extern , identyfikator ma połączenie zewnętrzne, a definicja wbudowana zawiera również definicję zewnętrzną.

Jeśli klasa pamięci to static, identyfikator jest powiązany wewnętrznie, a definicja wbudowana jest niewidoczna w innych jednostkach tłumaczeniowych.

Jeśli klasa pamięci nie jest określona, ​​definicja wbudowana jest widoczna tylko w bieżącej jednostce tłumaczeniowej, ale identyfikator nadal jest powiązany z zewnętrzną linią i należy podać definicję zewnętrzną w innej jednostce tłumaczeniowej. Kompilator może swobodnie używać definicji wbudowanej lub zewnętrznej, jeśli funkcja jest wywoływana w ramach bieżącej jednostki tłumaczenia.

Ponieważ kompilator może wbudować (a nie wbudować) dowolną funkcję, której definicja jest widoczna w bieżącej jednostce tłumaczeniowej (a dzięki optymalizacji czasu łącza, nawet w różnych jednostkach tłumaczeniowych, chociaż standard C tak naprawdę nie uwzględnia that), z większości praktycznych powodów nie ma różnicy między definicjami funkcji statica static inline.

Specyfikator inline(podobnie jak registerklasa pamięci masowej) jest tylko wskazówką kompilatora, a kompilator może go całkowicie zignorować. Zgodne ze standardami nieoptymalizujące kompilatory muszą tylko uwzględniać ich skutki uboczne, a optymalizujące kompilatory będą przeprowadzać te optymalizacje z lub bez wyraźnych wskazówek.

inlinei registernie są jednak bezużyteczne, ponieważ instruują kompilator, aby zgłaszał błędy, gdy programista pisze kod, który uniemożliwiłby optymalizacje: inlinedefinicja zewnętrzna nie może odwoływać się do identyfikatorów z powiązaniem wewnętrznym (ponieważ byłyby one niedostępne w innej jednostce tłumaczenia) lub zdefiniuj modyfikowalne zmienne lokalne ze statycznym czasem przechowywania (ponieważ nie będą one dzielić stanu w jednostkach tłumaczeniowych) i nie możesz wziąć adresówregister zmiennych kwalifikowanych.

Osobiście używam konwencji do oznaczania staticdefinicji funkcji również w nagłówkach inline, ponieważ głównym powodem umieszczania definicji funkcji w plikach nagłówkowych jest uczynienie ich inlinowalnymi.

Ogólnie rzecz biorąc, oprócz definicji używam tylko definicji static inlinefunkcji i static constobiektówextern deklaracji w nagłówkach .

Nigdy nie napisałem inlinefunkcji z inną klasą pamięci niż static.

Christoph
źródło
8
To jest poprawna odpowiedź. Każda odpowiedź mówiąca o tym inline, że faktycznie dotyczyła wstawiania, jest myląca i prawdopodobnie niepoprawna. Żaden współczesny kompilator nie używa go jako wskazówki do wstawiania lub wymagania tego w celu włączenia funkcji wstawiania w tekście.
Tyg13
1
upvoted dla "użyj konwencji do oznaczania definicji funkcji statycznych w nagłówkach w tekście".
John Z. Li
Przeczytałem całą twoją odpowiedź i nadal nie rozumiem semantycznej różnicy między statici static inline. Oba powodują, że definicja jest niewidoczna dla innych jednostek tłumaczeniowych. Więc jaki byłby rozsądny powód, żeby static inlinezamiast pisać static?
user541686
21

Z mojego doświadczenia z GCC wiem to statici static inlineróżni się sposobem, w jaki kompilator wyświetla ostrzeżenia o nieużywanych funkcjach. Dokładniej, gdy zadeklarujesz staticfunkcję i nie jest ona używana w bieżącej jednostce tłumaczącej, kompilator wyświetli ostrzeżenie o nieużywanej funkcji, ale możesz zablokować to ostrzeżenie, zmieniając je nastatic inline .

Dlatego uważam, że staticpowinien być używany w jednostkach tłumaczeniowych i korzystać z dodatkowego kompilatora sprawdzającego, aby znaleźć nieużywane funkcje. I static inlinepowinien być używany w plikach nagłówkowych, aby udostępniać funkcje, które można wstawić (z powodu braku zewnętrznych połączeń) bez wyświetlania ostrzeżeń.

Niestety nie mogę znaleźć żadnych dowodów na tę logikę. Nawet z dokumentacji GCC nie byłem w stanie wywnioskować, że inlineblokuje ostrzeżenia o nieużywanych funkcjach. Byłbym wdzięczny, gdyby ktoś udostępnił linki do opisu tego.

ony
źródło
1
Mmm, wciąż mamy warning: unused function 'function' [clang-diagnostic-unused-function]do static inlinefunkcji podczas budowania zclang-tidy (v8.0.1), który jest używany w innej jednostce tłumaczeniowej. Ale zdecydowanie jest to jedno z najlepszych wyjaśnień i powodów do łączenia static& inline!
DrumM
6

W C, static oznacza że zdefiniowana funkcja lub zmienna może być używana tylko w tym pliku (tj. Jednostce kompilacji)

Tak, static inlineoznacza funkcję inline, który może być używany tylko w tym pliku.

EDYTOWAĆ:

Jednostką kompilacyjną powinna być Jednostka tłumacząca

shengy
źródło
2
Lub wymyślnymi słowami: ma wewnętrzne powiązania.
K-ballo
@AlokSave: Czy istnieje różnica między jednostką kompilacji a jednostką tłumaczeniową ? Jeśli tak, co jest bardziej odpowiednie w kontekście języka C ++?
legends2k
Myślę, że the compile unitjest coś, co napisałem przez pomyłkę, nie ma czegoś takiego, rzeczywista terminologia totranslation unit
shengy
Twoja odpowiedź nie jest kompletna, ponieważ jest używana głównie w plikach nagłówkowych, w jednostkach tłumaczeniowych.
DrumM
5

Jedna różnica, która nie dotyczy poziomu języka, ale popularnego poziomu implementacji: niektóre wersje gcc static inlinedomyślnie usuwają funkcje, do których nie ma odniesień, z wyjścia, ale zachowują zwykłe staticfunkcje, nawet jeśli nie mają odniesień. Nie jestem pewien, które wersje to dotyczy, ale z praktycznego punktu widzenia oznacza to, że może to być dobry pomysł, aby zawsze korzystać inlinez staticfunkcji w nagłówkach.

R .. GitHub PRZESTAŃ POMÓC LODOWI
źródło
A co z używaniem inlinew definicji? Czy sugerujesz również, że nie używasz go do externfunkcji?
new_perl
Czy nadal tak jest w przypadku najnowszej wersji GCC? Twoja odpowiedź byłaby o wiele bardziej interesująca, gdybyś podał przykład i wymienił, która wersja GCC to robi.
Bozon Z
@Zboson: Nie mam tych informacji łatwo dostępnych i nie mam w tej chwili czasu na konfigurację i testowanie wielu wersji gcc, ale zgadzam się, że byłoby to przydatne. Prawdopodobnie można się było dowiedzieć, kiedy gcc po raz pierwszy zaczął optymalizować nieużywane statyczne funkcje / obiekty, patrząc na historię attribute((used))i jego użycie, aby umożliwić asm odwoływanie się do staticfunkcji i danych bez odniesień .
R .. GitHub PRZESTAŃ POMÓC W LODZIE