11 Ocak 2017 Çarşamba

C++ inline fonksiyon, önişlemci (preprocessor)


C++'da  önişlemci(preprocessor)/önişleme derleme işlemiminin bir parçası değildir, daha önce gerçekleştirilen bir aşamadır. Önişlemci adı üstünde olduğu gibi derleme işleminden önce kaynak kod üzerinde bir takım düzenlemeler/değişiklikler yapar. # karakteri ile başlayan satırlar önişlemci tarafından işlenir.



Örneğin;

#define MAX_ARRAY_LENGTH 20

bu satır ile kaynak kodda MAX_ARRAY_LENGTH görülen her yere 20 değeri yazılır.

Önişlemci ile fonksiyona benzer şekilde makrolar da yazılabilir. Mesela aşağıdaki gibi bir makro tanımlarsak;

#define square(a) a*a

square(7)  -> satırı 49 değerini döndürür.

Fakat;

square(2+3)  -> şu şekilde işlem görür : 2+3*2+3

Çünkü önişlemci kaynak kod üzerinde sadece değişiklik yapar, yani #define ile gördüğü değişken ile ilgili makroyu yer değiştirir. Tip kontrol gibi fonksiyonda gerçekleştirilen işlemleri yapmaz, Ayrıca debug işlemi de uygulanamaz. Bunlar makro kullanmanın  dezavantajlarıdır.


Yukarıdaki makroyu şu şekilde düzenlersek;

#define square(a) (a)*(a)

square(2+3) -> (2+3)*(2+3) = 25 , doğru değeri verecektir.

Makro da derleme işleminden evvel kaynak kod düzenlendiğinden ilgili kodlar/değerler kaynak koda yerleştirilir. Fonksiyonda ise sürekli ilgili fonksiyon çağrılır. Bu sebeple makro kullanmak execution time (çalışma süresini) düşürür. Yani kod daha hızlı çalışır!!!

Bir örnek üzerinden aynı işi yapan makro ve fonksiyonların (normal ve inline fonksiyon) çalışma sürelerini karşılaştırırsak;



Yukarıdaki kodda çalışma süreleri karşılaştırıldığında:

MULT (makro) çalışma süresi ->  22.5734 sn

normal fonksiyon çalışma süresi->  29.9154 sn

inline fonksiyon çalışma süresi ->  33.7718 sn


Yukarıdaki teste göre en hızlı makro çalıştı. Makro kullanmanın her ne kadar daha hızlı olsa da çeşitli dezavantajlarından bahsettik. Hem fonksiyon kullanalım hem de azcık daha hızlı çalışsın diyorsak, ihtiyacımız olan şey inline fonksiyon. inline fonksiyon da yine derleme aşamasında işleniyor fakat derleyici inline fonksiyonu gördüğü yere bu fonksiyonun içeriğini kopyalıyor. Bu sebeple inline fonksiyonda herhangi bir değişiklik yapıldığında bu fonksiyonu kullanan tüm kaynakların/dosyaların tekrardan derlenmesi gerekiyor. Normalde fonksiyon çağrıldığı zaman derleyici programın kaldığı adres bilgisini saklar ve ilgili fonksiyona dallanır. Bu fonksiyon içerisindeki değişkenler, alınan parametreler vs. oluşturulur ve işlem yapıldıktan sonra program kaldığı yerden devam eder. Yukarıdaki örneğe baktığımızda inline fonksiyonun normal fonksiyona nazaran daha yavaş kaldığını gözlüyoruz. Bunun sebebi şu olabilir:  derleyici zaten kod üzerinden optimizasyon uyguluyor!! Yani belki de bizim hangi fonksiyonu inline hangisini normal yapacağını modern derleyicilere bildirmemize gerek yok :) Fakat yukarıdaki kodda aşağıdaki gibi küçük gibi değişiklik yapıp, tekrar derlediğimizde:


(Fonksiyonların içerisine dizi ekledik)

int fonk(int a, int b)
{   int arr[3]={5,6,7};
    return (a + b)*(a + b) ;
}

inline int fonk_inline(int a, int b)
{
    int arr[3]={5,6,7};
    return (a + b)*(a + b) ;
}


normal fonksiyon çalışma süresi ->  46.9985 sn

inline fonksiyon çalışma süresi ->  44.6575 sn


Gördüğünüz gibi fonksiyonların içerisine küçük boyutlu da olsa bir dizi eklediğimizde inline fonksiyon daha hızlı çalıştı!! Sonuç olarak sanırım şunu söyleyebiliriz, çok küçük basit işler yapılacaksa makrolar çook çook daha hızlı, fonksiyon kullanmak ise biraz daha karmaşık işlemler için tabiki daha mantıklı ve inline fonksiyon kullanım yerine göre biraz daha hızlı olabilmekte.



2 yorum:

  1. İbrahim bu emeğin için teşekkür ederim. Umarım paylaşımların sürekli daha kaliteli hale gelir. Çalışmalarının devamını dilerim

    YanıtlaSil