Inline funkce - Inline function
![]() | Tento článek musí být aktualizováno. Důvod je uveden: Význam inline změněn v C ++ (https://en.cppreference.com/w/cpp/language/inline ). (Dubna 2019) |
V C a C ++ programovací jazyky, an inline funkce je jeden kvalifikovaný s klíčové slovo v souladu
; to slouží dvěma účelům. Za prvé slouží jako a směrnice kompilátoru který naznačuje (ale nevyžaduje), aby překladač nahradit tělo funkce inline provedením inline expanze, tj. vložením funkčního kódu na adresu každého volání funkce, čímž se ušetří režie volání funkce. V tomto ohledu je to obdoba Registrovat
specifikátor třídy úložiště, který podobně poskytuje optimalizační nápovědu.[1]Druhý účel v souladu
je změnit chování propojení; podrobnosti jsou komplikované. To je nutné kvůli C / C ++ samostatnému modelu kompilace + propojení, konkrétně proto, že definice (tělo) funkce musí být duplikována ve všech překladové jednotky kde se používá, umožnit vložení během kompilace, který, pokud má funkce externí vazba, způsobí kolizi během propojení (narušuje jedinečnost vnějších symbolů). C a C ++ (a dialekty jako GNU C a Visual C ++) to řeší různými způsoby.[1]
Příklad
An v souladu
funkce může být napsána v C nebo C ++ takto:
v souladu prázdnota vyměnit(int *m, int *n){ int tmp = *m; *m = *n; *n = tmp;}
Potom prohlášení, jako je následující:
vyměnit(&X, &y);
lze přeložit do (pokud se kompilátor rozhodne provést vložení, což obvykle vyžaduje povolení optimalizace):
int tmp = X;X = y;y = tmp;
Při implementaci třídicího algoritmu provádějícího spoustu swapů to může zvýšit rychlost provádění.
Standardní podpora
C ++ a C99, ale ne jeho předchůdci K&R C. a C89, mít podporu pro v souladu
funkce, i když s odlišnou sémantikou. V obou případech, v souladu
nevynucuje vložení; překladač se může svobodně rozhodnout, že funkci nezaradí vůbec, nebo pouze v některých případech. Různé překladače se liší v tom, jak složitou funkci mohou zvládnout inline. Mainstreamové kompilátory C ++ se líbí Microsoft Visual C ++ a GCC podporovat možnost, která umožňuje překladačům automaticky vkládat všechny vhodné funkce, a to i ty, které nejsou označeny jako v souladu
funkce. Jednoduše však vynechejte v souladu
klíčové slovo, aby překladač mohl učinit všechna rozhodovací rozhodnutí, není možné, protože linker si poté stěžuje na duplicitní definice v různých překladových jednotkách. To je proto, že v souladu
nejen dává kompilátoru nápovědu, že funkce by měla být vložena, ale má také vliv na to, zda kompilátor vygeneruje volanou out-of-line kopii funkce (viz třídy ukládání vložených funkcí ).
Nestandardní rozšíření
GNU C., jako součást dialektu gnu89, který nabízí, má podporu pro v souladu
jako rozšíření C89. Sémantika se však liší od C ++ i C99. armcc v režimu C90 také nabízí v souladu
jako nestandardní rozšíření se sémantikou odlišnou od gnu89 a C99.
Některé implementace poskytují prostředky, kterými donutit kompilátor k vložení funkce, obvykle pomocí specifikátorů deklarací specifických pro implementaci:
- Microsoft Visual C ++:
__forceinline
- gcc nebo clang:
__attribute __ ((always_inline))
nebo__attribute __ ((__ always_inline__))
, z nichž druhý je užitečný, aby se zabránilo konfliktu s uživatelem definovaným makrem s názvemalways_inline
.
Nerozlišující použití může mít za následek větší kód (nafouklý spustitelný soubor), minimální nebo žádný nárůst výkonu a v některých případech dokonce ztrátu výkonu. Kompilátor navíc nemůže za každých okolností inline funkci, i když je inlining vynucený; v tomto případě gcc i Visual C ++ generují varování.
Vynucení vložení je užitečné, pokud
v souladu
není kompilátorem respektován (ignorován analyzátorem nákladů a přínosů kompilátoru) a- vložení vede k nezbytnému zvýšení výkonu
Pro přenositelnost kódu lze použít následující direktivy preprocesoru:
#ifdef _MSC_VER #define forceinline __forceinline#elif definováno (__ GNUC__) #define forceinline inline __attribute __ ((__ always_inline__))#elif definováno (__ CLANG__) #if __has_attribute (__ always_inline__) #define forceinline inline __attribute __ ((__ always_inline__)) #jiný #define forceinline inline #endif#jiný #define forceinline inline#endif
Třídy úložiště vložených funkcí
statické vložené
má stejné účinky ve všech dialektech jazyka C a C ++. V případě potřeby vydá místně viditelnou (out-of-line kopii) funkce.
Bez ohledu na třídu úložiště může kompilátor ignorovat v souladu
kvalifikátor a vygenerovat volání funkce ve všech dialektech jazyka C a C ++.
Účinek třídy úložiště externí
při aplikaci nebo neaplikováno na v souladu
funkce se mezi dialekty C liší[2] a C ++.[3]
C99
V C99 je definována funkce v souladu
nikdy nebude a funkce definována extern inline
bude vždy vydávat externě viditelnou funkci. Na rozdíl od C ++ neexistuje způsob, jak požádat, aby byla externě viditelná funkce sdílená mezi překladovými jednotkami emitována pouze v případě potřeby.
Li v souladu
prohlášení jsou smíchána s extern inline
prohlášení nebo s nekvalifikovanými prohlášeními (tj. bez v souladu
kvalifikátor nebo třída úložiště), překladová jednotka musí obsahovat definici (bez ohledu na to, zda je v souladu
nebo extern inline
) a bude pro něj emitována externě viditelná funkce.
Definovaná funkce v souladu
vyžaduje přesně jednu funkci s tímto názvem někde jinde v programu, který je buď definován extern inline
nebo bez kvalifikace. Pokud je v celém programu poskytnuta více než jedna taková definice, linker si stěžuje na duplicitní symboly. Pokud však chybí, linker si nemusí nutně stěžovat, protože pokud by bylo možné uvést všechna použití, není to nutné. Může si ale stěžovat, protože překladač může vždy ignorovat v souladu
kvalifikátor a místo toho generovat volání funkce, jak se obvykle stane, pokud je kód kompilován bez optimalizace. (Může se jednat o požadované chování, pokud má být funkce všude všudypřítomná, a pokud není, měla by být vygenerována chyba.) Pohodlným způsobem je definovat v souladu
funkce v hlavičkových souborech a pro každou funkci vytvořte jeden soubor .c obsahující extern inline
prohlášení a včetně příslušného souboru záhlaví s definicí. Nezáleží na tom, zda je deklarace před nebo po zahrnutí.
Aby se zabránilo nedosažitelný kód od přidání do konečného spustitelného souboru, pokud by byla všechna použití funkce inline, doporučuje se[3] dát soubory objektů všech takových souborů .c do jediného extern inline
funkce do a statická knihovna soubor, obvykle s ar rcs
, pak namísto jednotlivých souborů objektů propojte tuto knihovnu. To způsobí propojení pouze těch objektových souborů, které jsou skutečně potřeba, na rozdíl od přímého propojení objektových souborů, což způsobí, že budou vždy zahrnuty do spustitelného souboru. Soubor knihovny však musí být zadán po všech ostatních souborech objektů na příkazovém řádku linkeru, protože linker nebude brát v úvahu volání ze souborů objektů zadaných po souboru knihovny funkcím. Hovory od v souladu
funkce jiným v souladu
funkce budou linkerem vyřešeny automaticky ( s
možnost v ar rcs
zajišťuje to).
Alternativním řešením je použití optimalizace doby propojení namísto knihovny. gcc poskytuje příznak -Wl, - gc-sekce
vynechat části, ve kterých nejsou všechny funkce používány. To bude případ objektových souborů obsahujících kód jednoho nepoužitého extern inline
funkce. Odebere však také všechny a všechny nepoužívané oddíly ze všech ostatních souborů objektů, nejen těch, které souvisejí s nepoužívanými extern inline
funkce. (Může být žádoucí propojit funkce do spustitelného souboru, které mají být volány programátorem z debuggeru, spíše než samotným programem, např. Pro zkoumání vnitřního stavu programu.) S tímto přístupem je také možné použít jeden soubor .c se všemi extern inline
funkce místo jednoho souboru .c na funkci. Poté musí být soubor zkompilován -fdata-sekce-funkční sekce
. Varuje však před tím stránka manuálu gcc, která říká: „Tyto možnosti používejte pouze v případě, že to má významné výhody.“
Někteří doporučují zcela odlišný přístup, kterým je definovat funkce jako statické vložené
namísto v souladu
v hlavičkových souborech.[2] Poté nebude vygenerován žádný nedosažitelný kód. Tento přístup má však nevýhodu v opačném případě: Duplicitní kód se vygeneruje, pokud funkci nelze vložit do více než jedné překladové jednotky. Vydaný funkční kód nelze sdílet mezi překladovými jednotkami, protože musí mít různé adresy. To je další nevýhoda; převzetí adresy takové funkce definované jako statické vložené
v záhlaví souboru přinese různé hodnoty v různých překladových jednotkách. Proto, statické vložené
funkce by měly být použity pouze v případě, že jsou použity pouze v jedné překladové jednotce, což znamená, že by měly jít pouze do příslušného souboru .c, nikoli do souboru záhlaví.
gnu89
gnu89 sémantika v souladu
a extern inline
jsou v podstatě pravým opakem těch v C99,[4] s tou výjimkou, že gnu89 umožňuje předefinování souboru extern inline
fungovat jako nekvalifikovaná funkce, zatímco C99 v souladu
ne.[5] Gnu89 extern inline
bez předefinování je jako C99 v souladu
a gnu89 v souladu
je jako C99 extern inline
; jinými slovy, v gnu89 je definována funkce v souladu
bude vždy a funkce definována extern inline
nikdy nevydá externě viditelnou funkci. Důvodem je to, že odpovídá proměnným, pro které nebude úložiště nikdy rezervováno, pokud bude definováno jako externí
a vždy, pokud je definováno bez. Důvodem pro C99 je naopak to, že by bylo udivující pokud používáte v souladu
by mělo vedlejší účinek - vždy vydávat nelineární verzi funkce - což je v rozporu s tím, co naznačuje její název.
Poznámky pro C99 o potřebě poskytnout přesně jednu externě viditelnou instanci funkce pro vložené funkce a o výsledném problému s nedosažitelným kódem platí mutatis mutandis také pro gnu89.
gcc až do verze 4.2 používané gnu89 v souladu
sémantika, i když -std = c99
bylo výslovně uvedeno.[6] U verze 5[5] gcc přešlo z gnu89 na dialekt gnu11, což účinně umožnilo C99 v souladu
sémantika ve výchozím nastavení. Chcete-li místo toho použít sémantiku gnu89, je nutné je explicitně povolit, buď s -std = gnu89
nebo ovlivnit pouze vložku, -fgnu89-inline
, nebo přidáním gnu_inline
atribut pro všechny v souladu
prohlášení. Chcete-li zajistit sémantiku C99, buď -std = c99
, -std = c11
, -std = gnu99
nebo -std = gnu11
(bez -fgnu89-inline
) může být použito.[3]
C ++
V C ++ je definována funkce v souladu
bude v případě potřeby vyzařovat funkci sdílenou mezi překladovými jednotkami, obvykle vložením do společné části souboru objektu, pro kterou je potřeba. Funkce musí mít všude stejnou definici, vždy s v souladu
kvalifikátor. V C ++, extern inline
je stejné jako v souladu
. Důvodem přístupu C ++ je, že je to pro programátora nejpohodlnější způsob, protože pro eliminaci nedostupného kódu není nutné dodržovat žádná zvláštní opatření a stejně jako u běžných funkcí nezáleží na tom, zda externí
je uvedeno nebo ne.
The v souladu
kvalifikátor se automaticky přidá k funkci definované jako součást definice třídy.
armcc
armcc v režimu C90 poskytuje extern inline
a v souladu
sémantika, která je stejná jako v C ++: Tyto definice budou v případě potřeby vyzařovat funkci sdílenou mezi překladovými jednotkami. V režimu C99 extern inline
vždy vydává funkci, ale stejně jako v C ++ bude sdílena mezi překladovými jednotkami. Lze tedy definovat stejnou funkci extern inline
v různých překladových jednotkách.[7] To odpovídá tradičnímu chování překladačů Unix C.[8] pro více ne-externí
definice neinicializovaných globálních proměnných.
Omezení
Převzetí adresy v souladu
funkce v každém případě vyžaduje kód pro nelineární kopii této funkce.
V C99, an v souladu
nebo extern inline
funkce nesmí mít přístup statický
globální proměnné nebo definovatkonst
statický
lokální proměnné. const statické
lokální proměnné mohou nebo nemusí být různé objekty v různých překladových jednotkách, v závislosti na tom, zda byla funkce vložena nebo zda bylo provedeno volání. Pouze statické vložené
definice mohou odkazovat na identifikátory s vnitřní vazbou bez omezení; to budou různé objekty v každé překladové jednotce. V C ++ obojí konst
a ne-konst
statický
místní jsou povoleni a odkazují na stejný objekt ve všech překladových jednotkách.
gcc nemůže inline funkce, pokud[3]
- oni jsou variadic,
- použití
aloka
- vypočítané použití
jít do
- používat nelokální
jít do
- použití vnořené funkce
- použití
setjmp
- použití
__builtin_longjmp
- použití
__builtin_return
nebo - použití
__builtin_apply_args
Na základě specifikací Microsoftu na MSDN nemůže MS Visual C ++ inline (ani s __forceinline
), pokud
- Funkce nebo její volající je kompilován s / Ob0 (výchozí možnost pro sestavení ladění).
- Funkce a volající používají různé typy zpracování výjimek (Zpracování výjimek C ++ v jednom, strukturované zpracování výjimek v druhém).
- Funkce má a seznam proměnných argumentů.
- Funkce používá inline montáž, pokud není kompilován s / Og, / Ox, / O1 nebo / O2.
- Funkce je rekurzivní a není doprovázen
#pragma inline_recursion (zapnuto)
. S pragmou jsou rekurzivní funkce vloženy do výchozí hloubky 16 hovorů. Pro zmenšení hloubky vložení použijteinline_depth
pragma. - Funkce je virtuální a je volána virtuálně. Přímé hovory na virtuální funkce lze podtrhnout.
- Program převezme adresu funkce a volání se provede pomocí ukazatele na funkci. Přímé hovory na funkce, u kterých byla přijata jejich adresa, lze inline.
- Funkce je také označena jako nahá
__declspec
modifikátor.
Problémy
kromě problémy s inline expanzí obecně, v souladu
funkce jako funkce jazyka nemusí být tak hodnotné, jak se zdá, z mnoha důvodů:
- Kompilátor je často v lepší pozici než člověk, aby rozhodl, zda má být konkrétní funkce vložena. Někdy kompilátor nemusí být schopen vložit tolik funkcí, kolik programátor označuje.
- Důležitým bodem je, že kód (
v souladu
funkce) je vystavena svému klientovi (volající funkci). - Jak se funkce vyvíjejí, mohou se stát vhodnými pro vložení tam, kde předtím nebyly, nebo již nebudou vhodné pro vložení tam, kde předtím byly. Zatímco vložení nebo odložení funkce je jednodušší než převod do az makra, stále vyžaduje zvláštní údržbu, která obvykle přináší relativně malou výhodu.
- Inline funkce používané při šíření v nativních kompilačních systémech založených na C mohou prodloužit dobu kompilace, protože do každého místa volání se zkopíruje zprostředkující reprezentace jejich těl.
- Specifikace
v souladu
v C99 vyžaduje přesně jednu externí definici funkce, pokud je někde použita. Pokud programátor takovou definici neposkytl, může to snadno vést k chybám linkeru. K tomu může dojít při vypnuté optimalizaci, která obvykle brání vložení. Přidání definic na druhé straně může způsobit nedosažitelný kód, pokud se tomu programátor pečlivě nevyhne, tím, že je umístí do knihovny pro propojení, pomocí optimalizace času propojení nebostatické vložené
. - V C ++ je nutné definovat
v souladu
funkce v každém modulu (překladové jednotce), který jej používá, zatímco běžná funkce musí být definována pouze v jednom modulu. Jinak by nebylo možné sestavit jeden modul nezávisle na všech ostatních modulech. V závislosti na kompilátoru to může způsobit, že každý příslušný objektový soubor bude obsahovat kopii kódu funkce pro každý modul s určitým použitím, které nelze inline. - v vestavěný software, často je nutné určité funkce umístit do určitých částí kódu pomocí speciálních instrukcí kompilátoru, jako jsou příkazy „pragma“. Někdy může funkce v jednom paměťovém segmentu vyžadovat volání funkce v jiném paměťovém segmentu, a pokud dojde k vložení volané funkce, kód volané funkce může skončit v segmentu, kde by neměl být. Například segmenty vysoce výkonné paměti mohou být v prostoru kódu velmi omezené a pokud funkce patřící do takového prostoru volá jinou velkou funkci, která nemá být v sekci s vysokým výkonem a volaná funkce je nevhodně vložena, pak to by mohlo způsobit, že segmentu vysoce výkonné paměti dojde místo v kódu. Z tohoto důvodu je někdy nutné zajistit, aby funkce fungovaly ne stát se podtrženým.
Citáty
- "Deklarace funkce [...] s v souladu specifikátor deklaruje inline funkci. The v souladu specifikátor označuje implementaci, že má být upřednostněna inline substituce těla funkce v místě volání před obvyklým mechanismem volání funkce. K provedení této inline substituce v místě volání není nutná implementace; i když je tato inline substituce vynechána, ostatní pravidla pro inline funkce definované v 7.1.2 musí být stále respektována. "
- - ISO / IEC 14882: 2011, aktuální standard C ++, oddíl 7.1.2
- "Funkce deklarovaná pomocí v souladu specifikátor funkce je vložená funkce. [. . . ] Vytvoření funkce jako vložené funkce naznačuje, že volání funkce bude co nejrychlejší. Rozsah, v jakém jsou tyto návrhy účinné, je definován implementací (poznámka pod čarou: Například implementace nemusí nikdy provádět inline substituci, nebo může provádět pouze inline substituce volání v rozsahu inline deklarace.)
- „[...] Vložená definice neposkytuje externí definici funkce a nezakazuje externí definici v jiné překladová jednotka. Vložená definice poskytuje alternativu k externí definici, kterou může překladatel použít k implementaci jakéhokoli volání funkce ve stejné překladové jednotce. Není uvedeno, zda volání funkce používá vloženou definici nebo externí definici. "
- - ISO 9899: 1999 (E), norma C99, oddíl 6.7.4
Viz také
Reference
- ^ A b Meyers, Randy (1. července 2002). „The New C: Inline Functions“. Citovat deník vyžaduje
| deník =
(Pomoc) - ^ A b http://www.greenend.org.uk/rjk/tech/inline.html
- ^ A b C d https://gcc.gnu.org/onlinedocs/gcc-7.1.0/gcc/Inline.html
- ^ http://blahg.josefsipek.net/?p=529
- ^ A b https://gcc.gnu.org/gcc-5/porting_to.html
- ^ https://gcc.gnu.org/ml/gcc-patches/2007-02/msg00119.html
- ^ http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka15831.html
- ^ manuální stránka gcc, popis
- neobvyklý
- JANA, DEBASISH (1. ledna 2005). C ++ A OBJEKTOVĚ ORIENTOVANÉ PROGRAMOVACÍ PARADIGM. PHI Learning Pvt. Ltd. ISBN 978-81-203-2871-6.CS1 maint: ref = harv (odkaz)
- Sengupta, Probal (1. srpna 2004). Objektově orientované programování: Základy a aplikace. PHI Learning Pvt. Ltd. ISBN 978-81-203-1258-6.CS1 maint: ref = harv (odkaz)
- Svenk, Goran (2003). Objektově orientované programování: Použití C ++ pro inženýrství a technologie. Cengage Learning. ISBN 0-7668-3894-3.CS1 maint: ref = harv (odkaz)
- Balagurusamy (2013). Objektově orientované programování v C ++. Tata McGraw-Hill Education. ISBN 978-1-259-02993-6.CS1 maint: ref = harv (odkaz)
- Kirch-Prinz, Ulla; Prinz, Peter (2002). Kompletní průvodce programováním v C ++. Jones & Bartlett Learning. ISBN 978-0-7637-1817-6.CS1 maint: ref = harv (odkaz)
- Conger, David (2006). Vytváření her v C ++: Podrobný průvodce. Noví jezdci. ISBN 978-0-7357-1434-2.CS1 maint: ref = harv (odkaz)
- Skinner, M. T. (1992). Pokročilá kniha C ++. Silicon Press. ISBN 978-0-929306-10-0.CS1 maint: ref = harv (odkaz)
- Láska (1. září 2005). Vývoj jádra Linuxu. Pearson Education. ISBN 978-81-7758-910-8.CS1 maint: ref = harv (odkaz)
- DEHURI, SATCHIDANANDA; JAGADEV, ALOK KUMAR; RATH, AMIYA KUMAR (8. května 2007). PROGRAMOVÁNÍ ORIENTOVANÉ NA OBJEKTY V C ++. PHI Learning Pvt. Ltd. ISBN 978-81-203-3085-6.CS1 maint: ref = harv (odkaz)
externí odkazy
- Inline funkce s Sbírka překladačů GNU (GCC)