top of page

C++ Dilinde inline...!

  • Writer: Yusuf Hançar
    Yusuf Hançar
  • Jun 4, 2023
  • 4 min read

Updated: Jun 13, 2023

Bir fonksiyonu çağıran yerde fonksiyonun yerine geçerek derleme zamanı çalışma verimini artırmak için kullanılır. C ve C++ dilleri için makine diline çevrilmeden önce derleyiciler tarafından optimize edildiklerinden bahsetmiştik. inline expansion kavramı da derleyicilerin yaptığı bir optimizasyondur. Bunu yaparken inline fonksiyonun içeriği kendisini çağıran kodda kullanılmaktadır. inline olarak tanımlanması derleyinin bahsettiğimiz şekilde optimizasyonu yapabilmesi için istekte bulunulmasıdır. Ancak bunun yapılacağı garanti edilmemektedir. inline fonksiyonların tanımında da bildiriminde de olabilir. Ancak birinde olması derleyiciye bildirmek için yeterli olacaktır. Çağrı yapılırken normal çağrı ile aynı formatta yapılmaktadır.

Birden fazla kez bulunmaları sınıf tanımlamaları ve C++17 ile gelen inline değişken tanımlayabilme özelliği gibi ODR(one definition rule) kuralını ihmal etmemektedir.

NOT : Fonksiyonların, değişkenlerin, enumaratörlerin, sınıf değişkenlerinin program içerisinde tek tanımlarının olmasıdır. Bildirimleri birden fazla kez yapılabilir.
inline return-type function-name(parameters) 
{ 
    // function code
}
// smartclass.h //
class SmartClass {
public :
};

inline int inl_func(int val)
{
    return 1;
}
*****************************
AÇIKLAMA: inl_func(...) global bir fonksiyondur ve ODR ihmal edilmemiştir. smartclass.h dosyasını projedeki diğer dosyalar include ederlerse bu sınıfın tanımı birden fazla kaynak dosyada olacaktır. Bu durum ODR kuralını ihmal etmesi gerekirken standartlara göre bunların tanımı token by token şeklindedir.
*****************************

Performans artışı istenen durum bunun kullanımı için tercih sebebidir. Tabi bunu yapmak hızlı olacak garantisi vermemektedir.

Program, fonksiyon çağrısı talimatını(instruction) yürüttüğünde; CPU, fonksiyon çağrısını takip eden komutun memory adresini saklar, fonksiyonun argümanlarını stack alanına kopyalar ve son olarak kontrolü belirtilen fonksiyona aktarır. CPU daha sonra fonksiyon kodunu yürütür, fonksiyon dönüş değerini önceden tanımlanmış bir memory location/register alanında saklar ve kontrolü çağıran fonksiyona geri verir. Bu, işlevin execution süresi, arayan işlevden çağrılan işleve geçiş süresinden daha az ise, ek yük(overhead) haline gelebilir. Büyük ve karmaşık görevler gerçekleştiren işlevler için, işlev çağrısının ek yükü, işlevin çalışması için geçen süre ile karşılaştırıldığında genellikle önemsizdir. Ancak, yaygın olarak kullanılan küçük işlevler için, işlev çağrısını yapmak için gereken süre, genellikle işlevin kodunu gerçekten yürütmek için gereken süreden çok daha fazladır. Bu ek yük, küçük işlevler için oluşur, çünkü küçük işlevin yürütme süresi, anahtarlama süresinden daha azdır. İşte C++ bu overhead durumu azaltmak için inline fonksiyon ile çözüm sunmaktadır. Çağrıldığı zaman satırda genişletilen bir işlevdir. Bu fonksiyon küçük ise verimliliği artmaktadır diyebiliriz. Tekrar hatırlatmak gerekir ise derleyiciye yapılan bir istektir, komut değildir.


  • Derleyiciler yapılan inline isteğini aşağıdaki durumlarda reddedebilmektedir :

1) Bir fonksiyon bir döngü içeriyorsa,(for, while, do-while)

2) Bir fonksiyon statik variable içeriyorsa,

3) Bir fonksiyon özyinelemeli(recursive) ise,

4) Bir işlevin return type değeri geçersiz değilse ve return ifadesi işlev gövdesinde yoksa.

5) Bir fonksiyon switch veya goto deyimi içeriyorsa.


  • inline kullanımının avantajlarını maddeler halinde sıralarsak :

1)Fonksiyon çağrısı ek yükü oluşmaz.

2)Ayrıca fonksiyon çağrıldığında stack alanda push/pop değişkenlerinin ek yükünü de kaydeder.

3)Ayrıca, bir fonksiyondan geri dönüş çağrısının ek yükünden de tasarruf sağlar.

4)Derleyicinin fonksiyon gövdesi üzerinde bağlama özel optimizasyon gerçekleştirmesini sağlayabilirsiniz. Normal fonksiyon çağrıları için bu tür optimizasyonlar mümkün değildir. Çağıran bağlam ve çağrılan bağlamın akışları dikkate alınarak diğer optimizasyonlar elde edilebilir.

5)Gömülü sistemler için yararlı olabilir (eğer küçükse), çünkü inline function çağrısı giriş ve dönüşünden daha az kod sağlayabilir.


  • inline kullanımının dezavantajlarını maddeler halinde sıralarsak :

1) inline fonksiyondan eklenen değişkenler ek register tüketir, satır içi işlevden sonra, register kullanacak değişken sayısı artarsa, register değişkeni kaynak kullanımında ek yük oluşturabilirler. Bu, işlev çağrısı noktasında inline fonksiyon gövdesi değiştirildiğinde, fonksiyon tarafından kullanılan toplam değişken sayısının da ekleneceği anlamına gelir. Böylece değişkenler için kullanılacak register sayısı da artacaktır. Bu nedenle, fonksiyon inline değişken sayılarından sonra büyük ölçüde artarsa, bu kesinlikle register kullanımında bir ek yüke neden olur.

2) Çok fazla inline fonksiyon kullanılırsa, aynı kodun tekrarlanması nedeniyle ikili çalıştırılabilir dosyanın boyutu büyük olacaktır.

3) Çok fazla inline fonksiyon, instruction cache isabet oranını(hit rate) da azaltabilir, böylece instruction fetch hızını önbellekten primary memory'e düşürür.

4) Birisi inline fonksiyonun içindeki kodu değiştirirse derleme süresini artırabilir, bu durumda tüm arama konumunun yeniden derlenmesi gerekir çünkü derleyici değişiklikleri yansıtmak için tüm kodu bir kez daha değiştirmeyi gerektirecektir, aksi takdirde eski işlevsellikle devam edecektir. .

5) inline fonksiyonlar, birçok gömülü sistem için kullanışlı olmayabilir. Çünkü gömülü sistemlerde kod boyutu hızdan daha önemlidir.

6) inline, binary executable file boyutunu artırabileceğinden, thrashing durumuna neden olabilir. Bellekteki thrashing, bilgisayarın performansının düşmesine neden olur.


#include <iostream>

using namespace std;

inline int square(int sq) 
{ 
    return sq*sq; 
}

int main() 
{ 
    cout << "The square of 5 is: " << square(5) << "\n"; 
    return 0; 
} 
// smartclass.h //

class SmartClass {
public :
    int inl_func(int); 
};

inline int SmartClass::inl_func(int idx)
{
    return idx*idx;
}
*****************************
AÇIKLAMA: sınıfın member fonksiyonunun inline olması durumudur.
*****************************
// smartclass.h //

class SmartClass {
public :
    inline int inl_func(int idx)
    {
        return idx*idx;
    }
};
*****************************
AÇIKLAMA: header dosyasında inline yazılıp yazılmaması durumu etkilemez. Her durumda inline durumdadır.
*****************************

NOT : Static function, non-static member function, friend function sınıf içinde inline tanımlanabilmektedir.
// smartclass.h //

class SmartClass {
public :
    static int inl_func(int idx)
    {
        return idx*idx;
    }
};
// smartclass.h //

class SmartClass {
public :
    friend int inl_func(int idx)
    {
        return idx*idx;
    }
};
*****************************
AÇIKLAMA: normalde global fonksiyonlar sınıf içerisinde tanımlanamazlar ancak friend ise buradaki gibi sınıf içinde inline tanımlanabilmektedirler.
*****************************
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template<typename T>
class SmartClass {
private:
    std::vector<T> data;

public:
    void add(const T& value) 
    {
        data.push_back(value);
    }

    vector<T> inl_func(const function<bool(const T&)>& predicate) const 
    {
        vector<T> res;
        
        copy_if(data.begin(), data.end(), back_inserter(res), predicate);
        return res;
    }
};

int main() 
{
    SmartClass<int> sc;

    sc.add(15);
    sc.add(43);
    sc.add(22);
    sc.add(89);
    sc.add(61);

    auto odd_nums = sc.inl_func([](const int& val) 
    {
        return val % 2 != 0;
    });

    cout << "odd nums : ";
    
    for (const auto& num : odd_nums) 
    {
        cout << num << " ";
    }
    
    cout << endl;

    return 0;
}
*****************************
CEVAP: odd nums : 15 43 89 61 
*****************************

C++17 ile değişkenler de inline olarak tanımlanabilmektedirler. Aynı isimle birden fazla kaynak dosyasında tanımlanmasına izin vererek ortak bellek kullanmalarına olanak tanır.
// smartcode.h
inline int sc = 5;

// smartcode.cpp
#include "header.h"

Avantajları :
  1. Birden fazla kaynak dosyada aynı isimle kullanılıp moduler bir yapı ile esneklik sağlar.

  2. Ortak bellek alanı kullandıkları için verimi artırır.

  3. Derleme zamanını hızlandırmaktadır.

Dezavantajları :
  1. Aynı isimle kullanılabilmesi kullanıcının dikkatinin de etkisini artırmaktadır.

  2. Kodun büyüklüğüne göre her dosyada bu inline değişkenlerin değeri güncellendiği için derleme zamanını artırabilir.

  3. Uyumluluğu C++ standartlarına göre şekillendiği için dikkat edilmelidir.


static ve inline olarak tanımlama arasındaki farkları bilmek optimizasyonu yüksek bir kod yazmada faydalı olacaktır :


ree


 
 
 

Recent Posts

See All
C++ Dilinde [[nodiscard]] attribute

C++’ta [[attribute]] (öznitelik) mekanizması, kod hakkında ek bilgi sağlayarak derleyicinin uyarılar vermesine, belirli optimizasyonlar...

 
 
 
C++ Dilinde constinit

C++20'de tanıtılan önemli bir özellik `constinit`'dir; bu özellik, statik depolama süresine sahip değişkenlerin derleme zamanında...

 
 
 

Comments


bottom of page