Satır içi işlevler ve Önişlemci makroları


Yanıtlar:


127

Ö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:

  • Makrolar tip güvenli değildir ve sözdizimsel olarak doğru olup olmadıklarına bakılmaksızın genişletilebilir - derleme aşaması, makro genişletme sorunlarından kaynaklanan hataları bildirir.
  • Makrolar, beklemediğiniz bağlamda kullanılabilir ve sorunlara neden olabilir
  • Makrolar, diğer makroları genişletebildikleri için daha esnektir - oysa satır içi işlevler bunu yapmak zorunda değildir.
  • Makrolar, modelde göründükleri her yerde girdi ifadeleri kopyalandığından, genişlemeleri nedeniyle yan etkilere neden olabilir.
  • Satır içi işlevin her zaman satır içi olması garanti edilmez - bazı derleyiciler bunu yalnızca yayın sürümlerinde veya bunu yapacak şekilde özel olarak yapılandırıldıklarında yapar. Ayrıca, bazı durumlarda satır içi yapmak mümkün olmayabilir.
  • Satır içi işlevler değişkenler için kapsam sağlayabilir (özellikle statik olanlar), önişlemci makroları bunu yalnızca kod bloklarında yapabilir {...} ve statik değişkenler tam olarak aynı şekilde davranmaz.

39
Satır içi işlevin her zaman satır içi olması garanti edilmez: Çünkü derleyici satır içi olmayacak, eğer bunu yapmak daha yavaş kod üretecektir vb. Derleyici, Mühendisin yapamadığı ve doğru şeyi yaptığı çok sayıda analiz yapar.
Martin York

14
Yinelemeli işlevlerin, çoğu derleyicinin satır içi yapmayı göz ardı ettiği başka bir örnek olduğuna inanıyorum.
LBushkin

Bu durumda C ++ ile C ++ arasında önemli farklılıklar var mı?
rzetterberg

7
Belirtilmeyen bir nokta, satır içi yazmanın derleme bayraklarından etkilenebileceğidir. Örneğin, maksimum hız için derleme yaptığınızda (GCC -O2 / -O3 gibi) derleyici birçok işlevi satır içi yapmayı seçecektir, ancak minimum boyut (-Os) için oluşturduğunuzda, genellikle yalnızca bir kez (veya çok küçük işlevler) satır içi işlevler ). Makrolarda böyle bir seçenek yoktur.
dbrank 0

Satır içi işlevler mümkünken makrolar erişim tanımlayıcısını (özel veya korumalı gibi) kapsamaz.
Hit

78

İ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 ( aveya biki kez artırılacaktır). Bunun yerine (örneğin) kullanın

inline int max( int a, int b) { return ((a<b)?b:a); }

3
max(fibonacci(100), factorial(10000))
Örneğinize

Herkes Tip Kontrolü hakkında konuşuyor ama siz sadece gerçek dünyadan bir örnek sağladınız, bu yüzden bu cevaba oy verdim.
Ivanzinho

16

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).


13

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.


11

Halihazırda verilenlere başka bir fark eklemek için: #definehata ayıklayıcıda a'ya adım atamazsınız, ancak bir satır içi işlevden geçebilirsiniz.



3

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:

  • Satır içi işlevler, normal işlevlerde uygulanan tüm güvenlik türü protokollerini izler.
  • Satır içi işlevler, işlev bildirimine satır içi anahtar sözcüğünü içermeleri dışında diğer işlevlerle aynı sözdizimi kullanılarak belirtilir.
  • Satır içi işlevlere bağımsız değişken olarak iletilen ifadeler bir kez değerlendirilir.
  • 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

;


2

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.


1

Satır içi bir işlev, sözdizimsel olarak normal bir işlev gibi davranır, tür güvenliği ve işlev yerel değişkenleri için bir kapsam ve bir yöntemse sınıf üyelerine erişim sağlar. Ayrıca, satır içi yöntemleri çağırırken özel / korumalı kısıtlamalara uymanız gerekir.


1

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;
}
  • Makrolar önişleme aşamasında çalışır, yani bu aşamada # anahtar kelime ile yazılan ifadeler içerikle değiştirilecektir, örn.

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:

  1. Makrolar ikame yoluyla çalışır, oysa satır içi İşlevlerde işlev çağrısı gövde ile değiştirilir.
  2. Satır içi işlevlerin kullanımı güvenliyken, makrolar ikame nedeniyle hataya açıktır.
  3. Makroların adresi yoktur, oysa satır içi işlevlerin adresi vardır.
  4. Makroların birden çok kod satırıyla kullanılması zordur, oysa satır içi işlevler değildir.
  5. C ++ 'da makrolar üye işlevlerle kullanılamaz, oysa satır içi işlev olabilir.

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:

  • büyük fonksiyonlar
  • çok fazla koşullu argümana sahip işlevler
  • özyinelemeli kod ve döngüler vb. içeren kod

bu iyi bir şey, çünkü derleyici her şeyi başka bir şekilde yapmanın en iyisi olduğunu düşündüğü zamandır.


Bir açıklama olarak: Makro, parantezlerle aynı sayıyı değerlendirmek için sabitlenebilir. Bununla birlikte, mutlak aptal yerine koyma ve uygulama sırasındaki tüm durumlar hakkında düşünmeniz gerektiğinden, yine de hataya açıktır.
mike

0

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.


0

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.


0

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.


-1
#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 << nSonra ne kadar çok eğlenirsin cout << CUBE(TWO_N(3 + 1)) << endl;? (O ile çıktı satırları sonuna kadar iyidir endlonunla bunları başlamak daha.)
Jonathan Leffler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.