C++ gir innebygde funksjoner for å redusere funksjonsanropsoverhead. En innebygd funksjon er en funksjon som utvides i linje når den kalles. Når den innebygde funksjonen kalles, blir hele koden til den innebygde funksjonen satt inn eller erstattet ved punktet for det innebygde funksjonskallet. Denne erstatningen utføres av C++-kompilatoren på kompileringstidspunktet. En innebygd funksjon kan øke effektiviteten hvis den er liten.
Syntaks:
inline return-type function-name(parameters) { // function code }>
Husk at inlining bare er en forespørsel til kompilatoren, ikke en kommando. Kompilatoren kan ignorere forespørselen om inlining.
Kompilatoren kan ikke utføre inlining under slike omstendigheter som:
- Hvis en funksjon inneholder en løkke. ( for, mens og gjør-mens )
- Hvis en funksjon inneholder statiske variabler.
- Hvis en funksjon er rekursiv.
- Hvis en funksjonsreturtype er en annen enn void, og retursetningen ikke finnes i en funksjonstekst.
- Hvis en funksjon inneholder en switch eller goto-setning.
Hvorfor brukes inline-funksjoner?
Når programmet utfører funksjonsanropsinstruksjonen, lagrer CPU minneadressen til instruksjonen etter funksjonskallet, kopierer argumentene til funksjonen på stabelen og overfører til slutt kontrollen til den spesifiserte funksjonen. CPU-en utfører deretter funksjonskoden, lagrer funksjonens returverdi i et forhåndsdefinert minnested/register, og returnerer kontrollen til den kallende funksjonen. Dette kan bli overhead hvis utførelsestiden for funksjonen er mindre enn byttetiden fra oppringerfunksjonen til oppringt funksjon (callee).
For funksjoner som er store og/eller utfører komplekse oppgaver, er overheaden til funksjonsanropet vanligvis ubetydelig sammenlignet med hvor lang tid funksjonen tar å kjøre. Men for små, ofte brukte funksjoner, er tiden som trengs for å foreta funksjonsanropet ofte mye mer enn tiden som trengs for å faktisk utføre funksjonens kode. Denne overheaden oppstår for små funksjoner fordi utførelsestiden for en liten funksjon er mindre enn byttetiden.
Inline funksjoner Fordeler:
- Overhead for funksjonsanrop forekommer ikke.
- Den lagrer også overheaden til push/pop-variabler på stabelen når en funksjon kalles.
- Den lagrer også overheaden til et returanrop fra en funksjon.
- Når du legger inn en funksjon, kan du aktivere kompilatoren til å utføre kontekstspesifikk optimalisering av funksjonens hoveddel. Slike optimaliseringer er ikke mulig for vanlige funksjonskall. Andre optimaliseringer kan oppnås ved å vurdere flytene til den anropende konteksten og den kalte konteksten.
- En innebygd funksjon kan være nyttig (hvis den er liten) for innebygde systemer fordi inline kan gi mindre kode enn funksjonen som kalles preamble og retur.
Inline funksjon Ulemper:
- De tilføyde variablene fra den innebygde funksjonen bruker ytterligere registre. Etter in-lining-funksjonen, hvis variabeltallet som skal bruke registeret øker, kan de skape overhead på registervariabel ressursutnyttelse. Dette betyr at når den innebygde funksjonskroppen erstattes ved punktet av funksjonskallet, blir det totale antallet variabler som brukes av funksjonen også satt inn. Så antallet registre som skal brukes for variablene vil også øke. Så hvis etter funksjon inlining variable tall øker drastisk, vil det sikkert føre til overhead på registerutnyttelse.
- Hvis du bruker for mange innebygde funksjoner, vil størrelsen på den binære kjørbare filen være stor på grunn av dupliseringen av den samme koden.
- For mye inlining kan også redusere trefffrekvensen for instruksjonsbufferen, og dermed redusere hastigheten på instruksjonshentingen fra hurtigminnet til det primære minnet.
- Den innebygde funksjonen kan øke kompileringstiden overhead hvis noen endrer koden inne i den innebygde funksjonen, så må alle anropsstedene kompileres på nytt fordi kompilatoren vil bli pålagt å erstatte all koden igjen for å gjenspeile endringene, ellers vil den fortsette med gammel funksjonalitet.
- Innebygde funksjoner er kanskje ikke nyttige for mange innebygde systemer. Fordi i innebygde systemer er kodestørrelse viktigere enn hastighet.
- Inline-funksjoner kan forårsake thrashing fordi inlining kan øke størrelsen på den binære kjørbare filen. Trassing i minnet fører til at ytelsen til datamaskinen forringes. Følgende program demonstrerer bruken av den innebygde funksjonen.
Eksempel:
C++
#include> using> namespace> std;> inline> int> cube(>int> s) {>return> s * s * s; }> int> main()> {> >cout <<>'The cube of 3 is: '> << cube(3) <<>'
'>;> >return> 0;> }> |
>
>Produksjon
The cube of 3 is: 27>
Inline funksjon og klasser
Det er også mulig å definere inline-funksjonen inne i klassen. Faktisk er alle funksjonene definert inne i klassen implisitt innebygd. Dermed blir alle begrensningene for innebygde funksjoner også brukt her. Hvis du eksplisitt trenger å deklarere en innebygd funksjon i klassen, er det bare å erklære funksjonen inne i klassen og definere den utenfor klassen ved å bruke det innebygde nøkkelordet.
Syntaks:
class S { public: inline int square(int s) // redundant use of inline { // this function is automatically inline // function body } };> Stilen ovenfor anses som en dårlig programmeringsstil. Den beste programmeringsstilen er å bare skrive prototypen til funksjonen inne i klassen og spesifisere den som en inline i funksjonsdefinisjonen.
For eksempel:
class S { public: int square(int s); // declare the function }; inline int S::square(int s) // use inline prefix { }> Eksempel:
C++
// C++ Program to demonstrate inline functions and classes> #include> using> namespace> std;> class> operation {> >int> a, b, add, sub, mul;> >float> div>;> public>:> >void> get();> >void> sum();> >void> difference();> >void> product();> >void> division();> };> inline> void> operation ::get()> {> >cout <<>'Enter first value:'>;> >cin>> a;> >cout <<>'Enter second value:'>;> >cin>> b;> }> inline> void> operation ::sum()> {> >add = a + b;> >cout <<>'Addition of two numbers: '> << a + b <<>'
'>;> }> inline> void> operation ::difference()> {> >sub = a - b;> >cout <<>'Difference of two numbers: '> << a - b <<>'
'>;> }> inline> void> operation ::product()> {> >mul = a * b;> >cout <<>'Product of two numbers: '> << a * b <<>'
'>;> }> inline> void> operation ::division()> {> >div> = a / b;> >cout <<>'Division of two numbers: '> << a / b <<>'
'>;> }> int> main()> {> >cout <<>'Program using inline function
'>;> >operation s;> >s.get();> >s.sum();> >s.difference();> >s.product();> >s.division();> >return> 0;> }> |
>
java null-sjekking
>
Produksjon:
Enter first value: 45 Enter second value: 15 Addition of two numbers: 60 Difference of two numbers: 30 Product of two numbers: 675 Division of two numbers: 3>
Hva er galt med makroen?
Lesere som er kjent med C-språket vet at C-språket bruker makro. Forprosessoren erstatter alle makroanrop direkte innenfor makrokoden. Det anbefales å alltid bruke den innebygde funksjonen i stedet for makroen. I følge Dr. Bjarne Stroustrup er skaperen av C++-makroer nesten aldri nødvendig i C++, og de er utsatt for feil. Det er noen problemer med bruken av makroer i C++. Makroen kan ikke få tilgang til private medlemmer av klassen. Makroer ser ut som funksjonskall, men det er de faktisk ikke.
Eksempel:
C++
// C++ Program to demonstrate working of macro> #include> using> namespace> std;> class> S {> >int> m;> public>:> >// error> #define MAC(S::m)> };> |
>
>
Produksjon:
Error: '::' may not appear in macro parameter list #define MAC(S::m)>
C++ kompilator sjekker argumenttypene for innebygde funksjoner og nødvendige konverteringer utføres riktig. Forprosessormakroen er ikke i stand til å gjøre dette. En annen ting er at makroene administreres av forprosessoren og innebygde funksjoner administreres av C++-kompilatoren. Husk: Det er sant at alle funksjonene som er definert inne i klassen er implisitt inline og C++ kompilatoren vil utføre inline kall av disse funksjonene, men C++ kompilatoren kan ikke utføre inline hvis funksjonen er virtuell. Årsaken kalles til en virtuell funksjon er løst ved kjøretid i stedet for kompileringstid. Virtuell betyr å vente til kjøretid og inline betyr under kompilering, hvis kompilatoren ikke vet hvilken funksjon som skal kalles, hvordan kan den utføre inlining? En annen ting å huske på er at det bare er nyttig å gjøre funksjonen innebygd hvis tiden brukt under et funksjonskall er mer sammenlignet med funksjonskroppens utførelsestid.
Et eksempel der den innebygde funksjonen ikke har noen effekt i det hele tatt:
inline void show() { cout << 'value of S = ' << S << endl; }> Funksjonen ovenfor tar relativt lang tid å utføre. Generelt bør en funksjon som utfører en input-output (I/O) operasjon ikke defineres som inline fordi den bruker en betydelig mengde tid. Teknisk inlining av show()-funksjonen er av begrenset verdi fordi tiden I/O-setningen vil ta langt overstiger overheaden til et funksjonskall. Avhengig av kompilatoren du bruker, kan kompilatoren vise deg en advarsel hvis funksjonen ikke utvides inline.
Programmeringsspråk som Java og C# støtter ikke innebygde funksjoner. Men i Java kan kompilatoren utføre inlining når den lille endelige metoden kalles fordi endelige metoder ikke kan overstyres av underklasser, og kallet til en endelig metode løses på kompileringstidspunktet.
I C# kan JIT-kompilatoren også optimere kode ved å legge inn små funksjonskall (som å erstatte kroppen til en liten funksjon når den kalles i en sløyfe). Den siste tingen å huske på er at innebygde funksjoner er en verdifull funksjon i C++. Riktig bruk av innebygde funksjoner kan gi ytelsesforbedring, men hvis innebygde funksjoner brukes vilkårlig, kan de ikke gi bedre resultater. Med andre ord, ikke forvent en bedre ytelse av programmet. Ikke lag alle funksjoner i linje. Det er bedre å holde innebygde funksjoner så små som mulig.