Yanıtlar:
Önişlemci makroları, kodunuza uygulanan ikame modelleridir. Herhangi bir derleme başlamadan önce genişletmeleriyle değiştirildikleri için kodunuzun neredeyse her yerinde kullanılabilirler.
Satır içi işlevler, gövdesi doğrudan arama sitelerine enjekte edilen gerçek işlevlerdir. Yalnızca bir işlev çağrısının uygun olduğu yerlerde kullanılabilirler.
Şimdi, makrolar ve satır içi işlevleri işlev benzeri bir bağlamda kullanmakla ilgili olarak şunu unutmayın:
İlk olarak, önişlemci makroları derlemeden önce kodda "kopyala yapıştır" dır. Yani tür kontrolü yoktur ve bazı yan etkiler ortaya çıkabilir
Örneğin, 2 değeri karşılaştırmak istiyorsanız:
#define max(a,b) ((a<b)?b:a)
max(a++,b++)
Örneğin kullanırsanız yan etkiler ortaya çıkar ( a
veya b
iki kez artırılacaktır). Bunun yerine (örneğin) kullanın
inline int max( int a, int b) { return ((a<b)?b:a); }
max(fibonacci(100), factorial(10000))
Satır içi işlevi, derleyici tarafından genişletilir; burada makrolar, yalnızca metin ikamesi olan Ön İşlemci tarafından genişletilir.
İşlev çağrısı sırasında tür denetimi yapılırken makro çağırma sırasında tür denetimi yoktur.
Bağımsız değişkenlerin ve işlemlerin sırasının yeniden değerlendirilmesi nedeniyle makro genişletme sırasında istenmeyen sonuçlar ve verimsizlik meydana gelebilir. Örneğin
#define MAX(a,b) ((a)>(b) ? (a) : (b))
int i = 5, j = MAX(i++, 0);
sonuçlanır
int i = 5, j = ((i++)>(0) ? (i++) : (0));
Makro argümanları makro genişletmeden önce değerlendirilmez
#define MUL(a, b) a*b
int main()
{
// The macro is expended as 2 + 3 * 3 + 5, not as 5*8
printf("%d", MUL(2+3, 3+5));
return 0;
}
// Output: 16`
Return anahtar sözcüğü, işlevlerde olduğu gibi makrolarda değer döndürmek için kullanılamaz.
Satır içi işlevler aşırı yüklenebilir
Makrolara aktarılan simgeler, Token-Yapıştırma operatörü olarak adlandırılan ## operatörü kullanılarak birleştirilebilir.
Makrolar genellikle kod yeniden kullanımı için kullanılır, çünkü satır içi işlevler, işlev çağrısı sırasında ek süreyi (fazla zaman) ortadan kaldırmak için kullanılır (bir alt yordama atlamayı önleme).
Temel fark, tür denetlemesidir. Derleyici, girdi değerleri olarak ilettiklerinizin işleve geçirilebilecek türler olup olmadığını kontrol edecektir. Önişlemci makroları için bu doğru değildir - herhangi bir tür kontrolünden önce genişletilirler ve bu, ciddi ve tespit edilmesi zor hatalara neden olabilir.
Burada , ana hatları verilen daha az belirgin olan birkaç nokta daha var.
Halihazırda verilenlere başka bir fark eklemek için: #define
hata ayıklayıcıda a'ya adım atamazsınız, ancak bir satır içi işlevden geçebilirsiniz.
Makrolar ad alanlarını yok sayıyor. Ve bu onları kötü yapar.
satır içi işlevler makrolara benzer (çünkü işlev kodu, derleme zamanında çağrı noktasında genişletilir), satır içi işlevler derleyici tarafından çözümlenirken makrolar önişlemci tarafından genişletilir. Sonuç olarak, birkaç önemli fark vardır:
Bazı durumlarda, makrolara bağımsız değişken olarak iletilen ifadeler birden çok kez değerlendirilebilir. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx
makrolar ön derleme zamanında genişletilir, bunları hata ayıklama için kullanamazsınız, ancak satır içi işlevleri kullanabilirsiniz.
- iyi makale : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1
;
Satır içi bir işlev, değer anlamını korurken, bir önişlemci makrosu yalnızca sözdizimini kopyalar. Eğer bağımsız değişkeni birden çok kez kullanırsanız, önişlemci makrosu ile çok ince hatalar elde edebilirsiniz - örneğin, bağımsız değişken "i ++" gibi bir mutasyon içeriyorsa, bunun iki kez çalıştırılması oldukça şaşırtıcıdır. Satır içi bir işlevde bu sorun olmayacaktır.
Makro ve satır içi işlev arasındaki farkı bilmek için , öncelikle tam olarak ne olduklarını ve ne zaman kullanmamız gerektiğini bilmeliyiz.
FONKSİYONLAR :
int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
İşlevin yürütülmesi bittikten sonra nereye dönmesi gerektiğini bilmesi ve değeri yığın belleğinde saklaması gerektiğinden, işlev çağrılarının kendisiyle ilişkili ek yükü vardır.
Küçük uygulamalar için sorun olmayacak, ancak her saniye binlerce işlemin gerçekleştiği finansal uygulamalara bir örnek verelim, fonksiyon çağrılarıyla gidemeyiz.
MAKROLARI:
# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
int sonuç = Kare (x * x)
Ancak makroların kendisiyle ilişkili hataları vardır.
#define Square(x) x*x
int main() {
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Burada çıktı 36 değil 11'dir .
INLINE FONKSİYONLAR :
inline int Square(int x) {
return x * x;
}
int main() {
using namespace std;
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Çıkış 36
Satır içi anahtar kelime, derleyiciden işlev çağrısını işlevin gövdesiyle değiştirmesini ister, burada çıktı doğrudur çünkü önce ifadeyi değerlendirir ve sonra geçer. Dönüş adresini ve yığını depolamaya gerek olmadığından işlev çağrısı ek yükünü azaltır işlev argümanları için bellek gerekli değildir.
Makrolar ve Satır İçi İşlevler Arasında Karşılaştırma:
SONUÇ:
Satır içi işlevler bazen performansı artırdığı ve kullanımı güvenli olduğu ve işlev çağrısı ek yükünü azalttığı için makrolardan daha kullanışlıdır. Bu sadece derleyiciye bir istek, bazı işlevler şu şekilde satır içi olmayacak:
bu iyi bir şey, çünkü derleyici her şeyi başka bir şekilde yapmanın en iyisi olduğunu düşündüğü zamandır.
GCC'de (diğerlerinden emin değilim), bir işlevi satır içi olarak bildirmek, derleyici için sadece bir ipucudur. Günün sonunda, her çağrıldığında işlevin gövdesini içerip içermediğine karar vermek hala derleyiciye kalmıştır.
Satır içi işlevler ile önişlemci makroları arasındaki fark görece büyüktür. Önişlemci makroları sadece günün sonunda metin değişimidir. Derleyicinin argümanlar ve dönüş türü üzerinde tür denetimi yapma becerisinden çok fazla vazgeçersiniz. Argümanların değerlendirilmesi çok daha farklıdır (işlevlere ilettiğiniz ifadelerin yan etkileri varsa, hata ayıklama konusunda çok eğlenceli zaman geçireceksiniz). İşlevlerin ve makroların nerede kullanılabileceği konusunda ince farklılıklar vardır. Örneğin:
#define MACRO_FUNC(X) ...
MACRO_FUNC açıkça işlevin gövdesini tanımlar. Her durumda düzgün çalışması için özel dikkat gösterilmesi gerekir, bir işlev kullanılabilir, örneğin kötü yazılmış bir MACRO_FUNC,
if(MACRO_FUNC(y)) {
...body
}
Orada problem olmadan normal bir fonksiyon kullanılabilir.
Kodlama açısından, bir satır içi işlev bir işlev gibidir. Bu nedenle, bir satır içi işlev ile bir makro arasındaki farklar, bir işlev ve bir makro arasındaki farklarla aynıdır.
Derleme perspektifinden bakıldığında, bir satır içi fonksiyon bir makroya benzer. Doğrudan koda enjekte edilir, çağrılmaz.
Genel olarak, satır içi işlevleri, bazı küçük optimizasyonların karıştırıldığı düzenli işlevler olarak düşünmelisiniz. Çoğu optimizasyon gibi, gerçekten uygulamayı düşünüp önemsemeyeceğine karar vermek derleyiciye bağlıdır. Çoğu zaman derleyici, programcının çeşitli nedenlerle bir işlevi satır içi yapma girişimlerini memnuniyetle göz ardı eder.
satır içi işlevler, içinde herhangi bir yinelemeli veya özyinelemeli ifade varsa, komutların tekrar tekrar çalıştırılmasını önlemek için bir işlev çağrısı gibi davranacaktır. Programınızın genel belleğini kaydetmek oldukça yararlıdır.
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{
return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases.
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
return a*a*a;
}
int main()
{
cout<<NUMBER<<endl<<number()<<endl;
cout<<CUBE(1+3); //Unexpected output 10
cout<<endl<<cube(1+3);// As expected 64
return 0;
}
Makrolar, gerçek işlev çağrısı ek yükü içermedikleri için genellikle işlevlerden daha hızlıdır.
Makroların Bazı Dezavantajları: Tür denetimi yoktur. Basit değiştirmeye neden olduklarından hata ayıklamak zordur.Makro ad alanına sahip değildir, bu nedenle kodun bir bölümündeki makro diğer bölümü etkileyebilir. Makrolar, yukarıdaki CUBE () örneğinde gösterildiği gibi yan etkilere neden olabilir.
Makrolar genellikle tek satırlıdır. Ancak birden fazla satırdan oluşabilir. Fonksiyonlarda böyle bir kısıtlama yoktur.
#define TWO_N(n) 2 << n
Sonra ne kadar çok eğlenirsin cout << CUBE(TWO_N(3 + 1)) << endl;
? (O ile çıktı satırları sonuna kadar iyidir endl
onunla bunları başlamak daha.)