6.7.4 Specyfikatory funkcji
Nowością C99:inline
słów kluczowych, zaadaptowany z C ++, to funkcja-specifier , które mogą być wykorzystane tylko w deklaracji funkcji. Jest to przydatne w przypadku optymalizacji programów, które wymagają, aby definicja funkcji była widoczna w miejscu wywołania. (Należy zwrócić uwagę, że standard nie podejmuje próby określenia charakteru tych optymalizacji).
Widoczność jest zapewniona, jeśli funkcja ma powiązanie wewnętrzne lub jeśli ma powiązanie zewnętrzne, a wywołanie jest w tej samej jednostce tłumaczeniowej co definicja zewnętrzna. W takich przypadkach obecność
inline
słowa kluczowego w deklaracji lub definicji funkcji nie ma żadnego skutku poza wskazaniem preferencji, że wywołania tej funkcji powinny być optymalizowane w stosunku do wywołań innych funkcji zadeklarowanych bez inline
słowa kluczowego.
Widoczność jest problemem w przypadku wywołania funkcji z łączem zewnętrznym, gdy wywołanie jest w innej jednostce tłumaczeniowej niż definicja funkcji. W tym przypadku inline
słowo kluczowe pozwala jednostce tłumaczeniowej zawierającej wywołanie zawierać również lokalną lub wbudowaną definicję funkcji.
Program może zawierać jednostkę tłumaczeniową z definicją zewnętrzną, jednostkę tłumaczeniową z definicją wbudowaną oraz jednostkę tłumaczeniową z deklaracją, ale bez definicji funkcji. Połączenia w drugiej jednostce tłumaczeniowej będą normalnie używać definicji zewnętrznej.
Uznaje się, że wbudowana definicja funkcji jest inną definicją niż definicja zewnętrzna. Jeśli wywołanie jakiejś funkcji func
z łączeniem zewnętrznym występuje, gdy widoczna jest definicja wbudowana, zachowanie jest takie samo, jak w przypadku wywołania innej funkcji, powiedzmy
__func
, z połączeniem wewnętrznym. Program zgodny nie może zależeć od wywoływanej funkcji. To jest model inline w standardzie.
Program zgodny nie może polegać na implementacji używającej definicji wbudowanej ani nie może polegać na implementacji korzystającej z definicji zewnętrznej. Adres funkcji jest zawsze adresem odpowiadającym definicji zewnętrznej, ale gdy ten adres jest używany do wywołania funkcji, można użyć definicji wbudowanej. Dlatego poniższy przykład może nie zachowywać się zgodnie z oczekiwaniami.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Ponieważ implementacja może używać definicji wbudowanej dla jednego z wywołań saddr
i używać definicji zewnętrznej dla drugiego, operacja równości nie jest gwarantowana do wartości 1 (prawda). Pokazuje to, że obiekty statyczne zdefiniowane w definicji wbudowanej różnią się od odpowiadających im obiektów w definicji zewnętrznej. To zmotywowało ograniczenie nawet do zdefiniowania const
obiektu niebędącego przedmiotem tego typu.
Inlining został dodany do Standardu w taki sposób, że można go zaimplementować z istniejącą technologią konsolidatora, a podzbiór inliningu C99 jest kompatybilny z C ++. Osiągnięto to poprzez wymaganie, aby dokładnie jedna jednostka translacyjna zawierająca definicję funkcji wbudowanej była określona jako ta, która zapewnia zewnętrzną definicję funkcji. Ponieważ ta specyfikacja składa się po prostu z deklaracji, która albo nie zawiera inline
słowa kluczowego, albo zawiera oba inline
i extern
, zostanie również zaakceptowana przez tłumacza C ++.
Inlining w C99 rozszerza specyfikację C ++ na dwa sposoby. Po pierwsze, jeśli funkcja jest zadeklarowana
inline
w jednej jednostce tłumaczeniowej, nie musi być deklarowana inline
w każdej innej jednostce tłumaczeniowej. Pozwala to, na przykład, na funkcję biblioteczną, która ma być wbudowana w bibliotekę, ale dostępna tylko poprzez zewnętrzną definicję w innym miejscu. Alternatywa użycia funkcji opakowującej dla funkcji zewnętrznej wymaga dodatkowej nazwy; może to również negatywnie wpłynąć na wydajność, jeśli tłumacz w rzeczywistości nie wykonuje zastępowania w tekście.
Po drugie, wymóg, aby wszystkie definicje funkcji wbudowanej były „dokładnie takie same”, zostaje zastąpiony wymogiem, że zachowanie programu nie powinno zależeć od tego, czy wywołanie jest implementowane z widoczną definicją wbudowaną, czy też definicją zewnętrzną funkcjonować. Pozwala to na wyspecjalizowanie definicji wbudowanej w celu jej wykorzystania w określonej jednostce tłumaczeniowej. Na przykład zewnętrzna definicja funkcji bibliotecznej może zawierać sprawdzanie poprawności argumentów, które nie jest potrzebne w przypadku wywołań wykonywanych z innych funkcji w tej samej bibliotece. Te rozszerzenia mają pewne zalety; a programiści, którzy są zaniepokojeni kompatybilnością, mogą po prostu przestrzegać bardziej rygorystycznych reguł C ++.
Należy pamiętać, że to jest nie odpowiednie dla implementacje zapewnienie inline definicje standardowych funkcji bibliotecznych w standardowych nagłówków, ponieważ może to złamać trochę starszy kod redeclares standardowe funkcje biblioteczne po tym ich nagłówki. To inline
słowo kluczowe ma na celu jedynie zapewnienie użytkownikom przenośnego sposobu sugerowania wbudowanych funkcji. Ponieważ standardowe nagłówki nie muszą być przenośne, implementacje mają inne opcje, takie jak:
#define abs(x) __builtin_abs(x)
lub inne nieprzenośne mechanizmy wstawiania standardowych funkcji bibliotecznych.