Yanıtlar:
Birincisi, inline
bir fonksiyonun özellikleri sadece bir ipucudur. Derleyici bir inline
niteleyicinin varlığını veya yokluğunu tamamen yok sayabilir (ve çoğu zaman yapar) . Bununla birlikte, bir derleyici , sonsuz döngüyü açabildiği kadar, özyinelemeli bir işlevi satır içine alabilir. Sadece fonksiyonun "kilidini" açacağı seviyeye bir sınır koymak zorundadır.
Optimize edici bir derleyici şu kodu döndürebilir:
inline int factorial(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
int f(int x)
{
return factorial(x);
}
bu koda:
int factorial(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
int f(int x)
{
if (x <= 1)
{
return 1;
}
else
{
int x2 = x - 1;
if (x2 <= 1)
{
return x * 1;
}
else
{
int x3 = x2 - 1;
if (x3 <= 1)
{
return x * x2 * 1;
}
else
{
return x * x2 * x3 * factorial(x3 - 1);
}
}
}
}
Bu durumda, işlevi temel olarak 3 kez eğimledik. Bazı derleyiciler yapmak bu optimizasyon gerçekleştirin. MSVC ++, özyinelemeli işlevlerde (20'ye kadar inanıyorum) yapılacak satır içi düzeyini ayarlamak için bir ayara sahip hatırlıyorum.
Gerçekten de, derleyiciniz akıllı bir şekilde inline
işlemezse, d işlevinizin kopyalarını yinelemeli olarak eklemeyi deneyebilir ve sonsuz büyüklükte kod oluşturabilir. Bununla birlikte, modern derleyicilerin çoğu bunu tanıyacaktır. Bunlar:
Durum 2 için, birçok derleyicide #pragma
bunun yapılması gereken maksimum derinliği belirlemek için ayarlayabileceğiniz s vardır. In gcc ile, ayrıca komut satırından bu geçebilir --max-inline-insns-recursive
(Daha fazla bilgi görmek buraya ).
Derleyici bir çağrı grafiği oluşturur; bir döngü kendisini çağırarak tespit edildiğinde, fonksiyon artık belirli bir derinlikten sonra satır içine alınmaz (derleyici ne ayarlı olursa olsun n = 1, 10, 100).
Bazı özyinelemeli işlevler, onları sonsuza kadar etkili bir şekilde hizalayan döngülere dönüştürülebilir. Gcc'nin bunu yapabileceğine inanıyorum, ancak diğer derleyiciler hakkında bilmiyorum.
Bunun neden tipik olarak çalışmadığına dair verilen yanıtlara bakın.
"Dipnot" olarak, şablon meta programlaması kullanarak aradığınız efekti (en azından örnek olarak kullandığınız faktöriyel için) elde edebilirsiniz . Wikipedia'dan yapıştırma:
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
Derleyici, bu tür şeyleri tespit etmek ve önlemek için bir çağrı grafiği yapar. Böylece fonksiyonun satır içi değil kendisini çağırdığını görür.
Ancak esas olarak satır içi anahtar kelime ve derleyici anahtarları tarafından kontrol edilir (Örneğin, anahtar kelime olmadan bile otomatik satır içi küçük işlevlere sahip olabilirsiniz.) Çağrı ayıklama aynası korunmayacağından Hata ayıklama derlemelerinin hiçbir zaman satır içi olmaması gerektiğini belirtmek önemlidir. kodda oluşturduğunuz çağrılar.
"Derleyici bir işlevi satır içine alıp almayacağına nasıl karar verir?"
Bu, derleyiciye, belirtilen seçeneklere, derleyicinin sürüm numarasına, belki de ne kadar bellek bulunduğuna, vb.
Programın kaynak kodu hala satır içi işlevler için kurallara uymak zorundadır. İşlevin satır içine girilip girilmeyeceği, satır içine alınma olasılığına (bazı bilinmeyen sayıda) hazırlık yapmanız gerekir.
Vikipedi özyinelemeli makrolar genellikle yasadışı görünüyor oldukça zayıf bilgilendirilmiş. C ve C ++ özyinelemeli çağrıları önler, ancak bir çeviri birimi özyinelemeli gibi görünen makro kodu içererek yasadışı olmaz. Montajcılarda, yinelemeli makrolar genellikle yasaldır.
Bazı derleyiciler (Ie Borland C ++) koşullu ifadeler içeren satır içi kodu (if, case, while vb.) İçermez, bu nedenle örneğin özyinelemeli işlevi satır içine alınmaz.