logo

Sisäiset funktiot C++:ssa

C++ tarjoaa sisäisiä toimintoja, jotka vähentävät funktiokutsujen lisäkustannuksia. Sisäinen funktio on funktio, joka laajenee rivissä, kun sitä kutsutaan. Kun inline-funktiota kutsutaan, inline-funktion koko koodi lisätään tai korvataan rivin sisäisen funktion kutsun kohdassa. Tämän korvauksen suorittaa C++-kääntäjä käännöshetkellä. Inline-toiminto voi lisätä tehokkuutta, jos se on pieni.

Syntaksi:



inline return-type function-name(parameters) { // function code }>
Sisäinen toiminto c++:ssa

Muista, että rivitys on vain pyyntö kääntäjälle, ei komento. Kääntäjä voi jättää huomioimatta upotuspyynnön.

Kääntäjä ei saa suorittaa rivitystä seuraavissa olosuhteissa:

  1. Jos funktio sisältää silmukan. ( ajaksi, ajaksi ja tee-hetki )
  2. Jos funktio sisältää staattisia muuttujia.
  3. Jos funktio on rekursiivinen.
  4. Jos funktion palautustyyppi on muu kuin void ja return-lausetta ei ole funktion rungossa.
  5. Jos funktio sisältää kytkin- tai goto-käskyn.

Miksi sisäisiä toimintoja käytetään?

Kun ohjelma suorittaa funktiokutsukäskyn, CPU tallentaa funktiokutsua seuraavan käskyn muistiosoitteen, kopioi funktion argumentit pinoon ja siirtää lopuksi ohjauksen määritettyyn funktioon. CPU suorittaa sitten toimintokoodin, tallentaa funktion palautusarvon ennalta määritettyyn muistipaikkaan/rekisteriin ja palauttaa ohjauksen kutsuvaan funktioon. Tästä voi tulla ylimääräisiä kustannuksia, jos toiminnon suoritusaika on lyhyempi kuin kytkentäaika kutsujafunktiosta kutsuttuun toimintoon (callee).



Suurille ja/tai monimutkaisia ​​tehtäviä suorittaville funktioille funktiokutsun lisäkustannukset ovat yleensä merkityksettömiä verrattuna funktion suorittamiseen kuluvaan aikaan. Pienissä, yleisesti käytetyissä funktioissa funktiokutsuun tarvittava aika on kuitenkin usein paljon enemmän kuin funktion koodin suorittamiseen tarvittava aika. Tämä ylikuormitus tapahtuu pienille toiminnoille, koska pienen toiminnon suoritusaika on lyhyempi kuin kytkentäaika.

Sisäiset toiminnot Edut:

  1. Toimintokutsun lisäkustannuksia ei tapahdu.
  2. Se myös tallentaa pinon push/pop-muuttujien ylärajan, kun funktiota kutsutaan.
  3. Se säästää myös funktion paluukutsun yleiskustannukset.
  4. Kun lisäät funktion riviin, voit sallia kääntäjän suorittaa kontekstikohtaisen optimoinnin funktion rungolle. Tällaiset optimoinnit eivät ole mahdollisia normaaleille funktiokutsuille. Muita optimointeja voidaan saada ottamalla huomioon kutsukontekstin ja kutsutun kontekstin vuot.
  5. Sisäinen funktio voi olla hyödyllinen (jos se on pieni) sulautetuissa järjestelmissä, koska inline voi tuottaa vähemmän koodia kuin funktio, jota kutsutaan johdanto- ja paluutunnisteeksi.

Inline-toiminnon haitat:

  1. Sisällytetyn funktion lisätyt muuttujat kuluttavat ylimääräisiä rekistereitä. Sisäänrakennettu funktion jälkeen, jos rekisteriä käyttävien muuttujien määrä kasvaa, ne voivat luoda ylimääräisiä rekisterimuuttujien resurssien käyttöä. Tämä tarkoittaa, että kun rivin sisäinen funktion runko korvataan funktiokutsussa, lisätään myös funktion käyttämien muuttujien kokonaismäärä. Näin ollen myös muuttujille käytettävien rekisterien määrä kasvaa. Joten jos funktion rivityksen jälkeen muuttujien lukumäärä kasvaa rajusti, se aiheuttaisi varmasti ylimääräisiä rekisterin käyttöä.
  2. Jos käytät liian monta rivifunktiota, binäärisuoritettavan tiedoston koko on suuri saman koodin päällekkäisyyden vuoksi.
  3. Liiallinen upotus voi myös vähentää käskyvälimuistin osumaprosenttia, mikä vähentää käskyjen haun nopeutta välimuistista ensisijaiseen muistiin.
  4. Sisäinen toiminto voi lisätä käännösaikaa, jos joku muuttaa koodia rivifunktion sisällä, jolloin kaikki kutsuva sijainti on käännettävä uudelleen, koska kääntäjän on korvattava kaikki koodi uudelleen muutosten heijastamiseksi, muuten se jatkaa vanhalla toiminnallisuus.
  5. Sisäiset toiminnot eivät välttämättä ole hyödyllisiä monissa sulautetuissa järjestelmissä. Koska sulautetuissa järjestelmissä koodin koko on tärkeämpi kuin nopeus.
  6. Sisäiset toiminnot voivat aiheuttaa räjähdystä, koska upottaminen saattaa suurentaa suoritettavan binaaritiedoston kokoa. Muistin puskeminen heikentää tietokoneen suorituskykyä. Seuraava ohjelma esittelee rivifunktion käyttöä.

Esimerkki:

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;> }>

>

>

Lähtö

The cube of 3 is: 27>

Inline-funktio ja luokat

Luokan sisällä on myös mahdollista määritellä rivifunktio. Itse asiassa kaikki luokan sisällä määritellyt funktiot ovat implisiittisesti rivissä. Siten kaikkia sisäisten toimintojen rajoituksia sovelletaan myös tässä. Jos haluat nimenomaisesti ilmoittaa funktion luokassa, ilmoita funktio luokan sisällä ja määritä se luokan ulkopuolella käyttämällä inline-avainsanaa.

Syntaksi:

class S { public: inline int square(int s) // redundant use of inline { // this function is automatically inline // function body } };>

Yllä olevaa tyyliä pidetään huonona ohjelmointityylinä. Paras ohjelmointityyli on vain kirjoittaa funktion prototyyppi luokan sisään ja määrittää se funktion määrittelyssä rivin sisällä.

Esimerkiksi:

class S { public: int square(int s); // declare the function }; inline int S::square(int s) // use inline prefix { }>

Esimerkki:

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;> }>

>

nginx-muuttujat
>

Lähtö:

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>

Mitä vikaa makrossa on?

C-kieleen perehtyneet lukijat tietävät, että C-kieli käyttää makroa. Esiprosessori korvaa kaikki makrokutsut suoraan makrokoodissa. On suositeltavaa käyttää aina sisäistä toimintoa makron sijaan. Tohtori Bjarne Stroustrupin mukaan C++-makrojen luoja ei ole juuri koskaan tarpeellista C++:ssa ja ne ovat virhealttiita. C++:n makrojen käytössä on joitain ongelmia. Makro ei voi käyttää luokan yksityisiä jäseniä. Makrot näyttävät funktiokutsuilta, mutta eivät todellisuudessa ole.

Esimerkki:

C++




// C++ Program to demonstrate working of macro> #include> using> namespace> std;> class> S {> >int> m;> public>:> >// error> #define MAC(S::m)> };>

>

>

Lähtö:

Error: '::' may not appear in macro parameter list #define MAC(S::m)>

C++-kääntäjä tarkistaa sisäisten funktioiden argumenttityypit ja tarvittavat muunnokset suoritetaan oikein. Esiprosessorin makro ei pysty tekemään tätä. Toinen asia on, että makroja hallitsee esiprosessori ja sisäisiä toimintoja C++-kääntäjä. Muista: On totta, että kaikki luokassa määritellyt funktiot ovat implisiittisesti rivissä ja C++-kääntäjä suorittaa näiden funktioiden inline-kutsuja, mutta C++-kääntäjä ei voi suorittaa inline-toimintoa, jos funktio on virtuaalinen. Virtuaalifunktion kutsumisen syy ratkaistaan ​​ajon aikana käännösajan sijaan. Virtuaalinen tarkoittaa odottamista suoritusaikaan ja inline tarkoittaa kääntämisen aikana. Jos kääntäjä ei tiedä mitä funktiota kutsutaan, kuinka se voi suorittaa inline-toiminnon? Toinen asia, joka on muistettava, on, että funktion tekeminen riviin on hyödyllistä vain, jos funktiokutsun aikana käytetty aika on enemmän verrattuna funktion rungon suoritusaikaan.

Esimerkki, jossa inline-funktiolla ei ole vaikutusta ollenkaan:

inline void show() { cout << 'value of S = ' << S << endl; }>

Yllä olevan toiminnon suorittaminen kestää suhteellisen kauan. Yleensä toimintoa, joka suorittaa input-output (I/O) -toiminnon, ei pitäisi määritellä inline-toiminnoksi, koska se vie huomattavan paljon aikaa. Show()-funktion teknisesti sisällyttämisellä on rajallinen arvo, koska aika, jonka I/O-käsky kestää, ylittää huomattavasti funktiokutsun yleiskustannukset. Riippuen käyttämästäsi kääntäjästä kääntäjä saattaa näyttää varoituksen, jos toimintoa ei ole laajennettu riviin.

Ohjelmointikielet, kuten Java ja C#, eivät tue upotettuja toimintoja. Mutta Javassa kääntäjä voi suorittaa rivityksen, kun kutsutaan pientä lopullista menetelmää, koska alaluokat eivät voi ohittaa lopullisia menetelmiä ja lopullisen menetelmän kutsu ratkaistaan ​​käännösvaiheessa.

C#:ssa JIT-kääntäjä voi myös optimoida koodia sisällyttämällä pieniä funktiokutsuja (kuten korvaamalla pienen funktion rungon, kun sitä kutsutaan silmukassa). Viimeinen asia, joka tulee muistaa, on, että tekstin sisäiset funktiot ovat arvokas ominaisuus C++:ssa. Sisäisten toimintojen asianmukainen käyttö voi parantaa suorituskykyä, mutta jos sisäisiä toimintoja käytetään mielivaltaisesti, ne eivät voi tarjota parempia tuloksia. Toisin sanoen, älä odota ohjelman parempaa suorituskykyä. Älä sisällytä jokaista toimintoa. Sisäiset toiminnot on parempi pitää mahdollisimman pieninä.