Według tego, co czytam, kompilator nie jest zobowiązany do zastąpienia wywołanie funkcji inline funkcji z jej ciała, ale zrobi to, jeśli to możliwe. To dało mi thinking- dlaczego mamy słowo inline, czy tak jest w istocie? Dlaczego nie wszystkie funkcje Funkcja inline domyślnie i niech postać kompilatora, czy można go zastąpić połączenia z ciałem funkcji, czy nie?
c++
language-design
optimization
compilation
EpsilonVector
źródło
źródło
Odpowiedzi:
inline
wynosi od C; to nie był nowy w C ++.Istnieją słowa kluczowe C (
register
iinline
), które zostały zaprojektowane, aby umożliwić programistom pomoc w optymalizacji kodu. Są one obecnie na ogół ignorowane, ponieważ kompilatory mogą lepiej radzić sobie z przypisywaniem rejestrów i podejmowaniem decyzji, kiedy należy wstawić funkcje (w rzeczywistości kompilator może wstawić lub nie wstawić funkcji w różnych momentach). Generowanie kodu na nowoczesnych procesorach jest znacznie bardziej skomplikowane niż na bardziej deterministyczny ones Common kiedy Ritchie był wymyślając C.Jakie środki słowo teraz, w C ++, jest to, że może on mieć wiele identycznych definicji, i musi być zdefiniowane w każdej jednostce tłumaczeniowej, która go używa. (Innymi słowy, trzeba upewnić się, że może to być inlined.) Można mieć
inline
funkcję w nagłówku bez żadnych problemów, a funkcje składowe określone w definicji klasy są automatycznie skutecznieinline
.źródło
inline
.inline
był standaryzowany w C ++ pierwszy, choć było już dostępne jako rozszerzenie sprzedawca w C .... Tak, wydaje się, że dodano do standardu C w C99.inline
w C99 i późniejsze różnią się od zasadinline
w C ++.Początkowo
inline
była bardzo silna wskazówka, że wywołania funkcji należy inlined.Ale tylko gwarantuje efekt
inline
jest umożliwienie funkcją być zdefiniowana (efektywnie identycznie) w wielu jednostek tłumaczeniowych, np się umieszczenie definicji w pliku nagłówka.Obecnie niektóre kompilatory są bardzo chętnie po nutą inline np g ++. I niektóre kompilatory zabrać go mniej poważnie, na przykład Visual C ++. Ale wszyscy muszą przestrzegać gwarancji.
Szkoda, że te dwa znaczenia - Optymalizacja i podpowiedź, co moglibyśmy nazwać poziomu łącznika discardable definicja - przebywania z tego samego słowa kluczowego, ponieważ oznacza to, że praktycznie nie można mieć jednego bez drugiego.
To niefortunne, że również
inline
(albo lepiej, oddzielne słów kluczowych o discardable definicji) ¹cannot być zastosowane do danych .Zapotrzebowanie na poziomie łącznika discardable danych wzrosła jako moduły header tylko stają się coraz bardziej popularne. Na przykład, wiele sub-Boost biblioteki są tylko nagłówek.
Dla danych można jednak zastosować mały trick z szablonami. Zdefiniować go w jakiś szablon klasy zapewnić
typedef
parametrem szablonuvoid
(lub cokolwiek). To dlatego, że jedna definicja reguły czyni wyjątek specyficzny dla szablonów.Uwagi:
¹
inline
zmienne będą obsługiwane C ++ 17 .źródło
inline
.Dlaczego nie włączyć domyślnie wszystkich funkcji? Ponieważ jest to kompromis inżynieryjny. Istnieją co najmniej dwa rodzaje „optymalizacji”: przyspieszenie programu i zmniejszenie rozmiaru (powierzchni pamięci) programu. Inlining ogólnie przyspiesza. To pozbywa napowietrznej wywołania funkcji, unikając popychanie parametrów potem pociągając ze stosu. Jednak powoduje to również zwiększenie pamięci programu, ponieważ każde wywołanie funkcji musi teraz zostać zastąpione pełnym kodem funkcji. Aby jeszcze bardziej skomplikować sprawę, pamiętaj, że procesor przechowuje często używane fragmenty pamięci w pamięci podręcznej procesora, zapewniając ultra szybki dostęp. Jeśli sprawisz, że obraz pamięci programu będzie wystarczająco duży, Twój program nie będzie w stanie efektywnie korzystać z pamięci podręcznej, aw najgorszym przypadku wbudowanie może spowolnić program.
źródło
Aby zrozumieć „inline” trzeba zrozumieć historię i jak wyglądało życie 20 (i 30) lat temu.
Pisaliśmy kod na komputerach, które miały mało pamięci, więc kompilator nie był w stanie przetworzyć całego kodu tworzącego program za jednym razem. Kompilator działał również bardzo wolno, więc nie trzeba było ponownie kompilować kodu, który się nie zmienił - przejęcie 24 godzin (na komputerze kosztującym więcej niż samochód wyższej klasy) w celu rekompilacji całego kodu było normalne dla kilku projektów I pracował.
Dlatego każdy plik kodu został osobno skompilowany w pliki obiektowe. Każdy plik obiektowy zaczynał się listą wszystkich zawartych w nim funkcji wraz z „adresem” funkcji. Plik obiektowy zawierał także listę wszystkich funkcji, które wywołał w innych plikach obiektowych wraz z lokalizacją wywołania.
Łącznik najpierw przeczytać wszystkie pliki obiektów i zbudować listę wszystkich funkcji one eksportowane wraz z plikiem byli i nie ma adresu. Następnie ponownie odczytałby wszystkie pliki obiektowe, wyprowadzając je do pliku programu, jednocześnie aktualizując wszystkie wywołania funkcji „zewnętrznej” o adres funkcji.
Linker nie zmienił ani nie zoptymalizował kodu maszynowego wygenerowanego przez kompilator w żaden inny sposób niż w celu poprawienia odniesień do wywołań funkcji zewnętrznych. Linker był częścią systemu operacyjnego i wyprzedza większość kompilatorów. Kiedy ludzie pisali nowy kompilator, potrzebowali go do pracy z bieżącymi linkerami i do możliwości łączenia się z bieżącymi plikami obiektowymi, w przeciwnym razie wywołanie systemowe nie byłoby możliwe.
Kompilator widział tylko kod w kompilowanym pliku „.c” lub „.cpp” wraz ze wszystkimi dołączonymi plikami nagłówkowymi. Nie mógł więc dokonać żadnej optymalizacji opartej na kodzie w innych plikach „.c” lub „.cpp”.
Słowo kluczowe „inline” pozwoliło na zdefiniowanie treści funkcji (metody) w pliku nagłówkowym, umożliwiając kompilatorowi korzystanie z kodu funkcji podczas kompilacji kodu, który ją wywołuje. Na przykład powiedzieć, że miał klasę zbiórki określony w pylników plik .cpp, ta klasa będzie miała „isEmpty” metodę, która zawierała jedną linię kodu, nie byłoby wielkim przyspieszenie wynikowego programu, jeśli zamiast wywołania funkcji , wywołanie funkcji zastąpiono tej jednej linii.
Słowo kluczowe „inline” było wówczas postrzegane jako „tani i łatwy” sposób na enkapsulację danych przy jednoczesnym uniknięciu kosztów wywołań funkcji, bez których wielu programistów miałoby dostęp do prywatnych pól obiektu. (Makra, w których znacznie gorszy sposób „wstawiania” kodu jest powszechny w tym czasie).
Obecnie „linkery” zajmują się optymalizacją kodu i zwykle są pisane przez jakiś zespół jako kompilator. Kompilator często po prostu sprawdza kod jest poprawny i „okłady”, pozostawiając większość zadanie tworzenia kodu maszynowego do łącznika.
źródło
Zobaczmy, co standardowe mówi (podświetlony ważnych części pogrubione):
Tak więc, jeśli chcesz mieć pewność, należy zapoznać się z dokumentacją swojego kompilatora.
Inline wszystko jest złym pomysłem, ponieważ może to spowodować wiele powielanego kodu maszynowego ...
Musisz więc wiedzieć:
źródło
inline
, potwierdzając wiedzę jak PO wydaje się stracić część więc co jest powodem rdzeń dlaczego nie dostaje punkt. Dla jednego, aby uzyskać punkt on musi mieć wiedzę o tym, co znajduje się pod tym momencie ...Podam dobry powód za pomocą słowa kluczowego inline.
W systemie wbudowanym, takim jak drukarka biletów lub podobny mniejszy system. Procesor jest bardzo ograniczona i wywołanie funkcji (przygotowanie parametrów funkcji na stosie, zadzwoń, params pobrać ze stosu i umieścić z powrotem odebrać etc ..) może potrwać kilka ms do wykonania, obok samej funkcji.
Powiedzmy, że czas połączenia wynosi około 60 ms (tylko do wywołania, a nie rzeczywistej funkcji) i masz 50 iteracji (pętli lub iteracyjnych wywołań w drzewie).
Czas po prostu przejść do przodu i do tyłu z tego połączenia funkcja będzie miała 60 * 50 = 3000 (3 sekund).
Jeśli masz pamięć to na pewno zrobić, aby zapisać inline 3 sekundy.
Inline są więc zasadniczo używane, gdy potrzebujesz prędkości wykonania. W niektórych projektach, w które byłem zaangażowany, czas wywoływania był dłuższy niż czas wykonania, co jest klasyczną sytuacją, gdy należy używać funkcji inline.
źródło