2016-03-25 15 views
2

C++ 'da yeni başlayan biriyim ve bu makroları, gerektiğinde metni değiştirerek okuyabiliyorum. Bu durumda, bu .exe'nin daha hızlı çalışmasını sağlar mı? Ve bu nasıl bir satır içi işlevden farklı? ÖrneğinC++'da makrolar performansı artırıyor mu?

, aşağıdaki makro varsa:

#define SQUARE(x) ((x) * (x)) 

ve normal fonksiyonunu:

int Square(const int& x) 
{ 
    return x*x; 
} 

ve satır içi işlevi:

inline int Square(const int& x) 
{ 
    return x*x; 
} 

bu arasındaki temel farklar nelerdir üç ve özellikle satır içi işlevi ve makro arasında? Teşekkür ederim.

+2

İlk önce çalıştırınız. Daha sonra hızlı çalışın. Doğruluk önemli değilse, hiçbir şey yapmayan bir işlev en hızlıdır. Genel olarak, makroların bir işlevden daha doğru olması daha zordur. Profilleme, aksi belirtilmedikçe, makro satır içi fonksiyon mikro optimizasyonu genellikle boşa harcanır. – jxh

+1

"Makrolar metni değiştirerek çalışır" ve "Makrolar programınızı daha hızlı hale getirir" ifadesi neredeyse ilgisiz iki ifadedir. – immibis

+0

Neredeyse bir dupe: http://stackoverflow.com/questions/1137575/inline-functions-vs-preprocessor-macros – vsoftco

cevap

7

Mümkünse makroları kullanmaktan kaçınmalısınız. Satır içi işlevler, güvenli olduklarından her zaman daha iyi bir seçimdir. Bir satır içi işlevi bir makro kadar hızlı olmalıdır (gerçekten de derleyici tarafından belirtilmişse; inline anahtar sözcüğünün bağlayıcı olmadığını, ancak derleyiciye ipucu verilebileceğini unutmayın; bu, satır içi mümkün değilse göz ardı edebilir).

PS: stil meselesi olarak, int veya double gibi fundamental vardır parametre türleri için const Type& kullanmaktan kaçının. Başka bir deyişle, bir kopyayı performansı etkilemediğinden, örn., Bir başka deyişle,

kullanın. Daha fazla ayrıntı için this question. aptal Bunun anlamı desen B ile desen A'nın yerini ve:

+0

Hızlı cevap ve ipuçları için teşekkür ederiz. Bu şekilde yazdım (const Type &) çünkü okuduğum derslerden birinde "maliyet" i performans açısından kopyalar. Temel türler hakkında hiçbir şeyden bahsetmedi, ama şimdi sadece kullanıcı tanımlı türler için kullanacağımı düşünüyorum. Tekrar teşekkürler! –

+0

@GeorgeGabriel Rica ederim. Kursdaki açıklama doğruysa ve onu takip ederseniz hiçbir şey kaybetmezsiniz. Bununla birlikte, temel türler için, referansla geçirme, bir kopya kadar pahalıdır, çünkü dahili olarak verilerin göstericisinin bir kopyası etrafından geçirilir. Ve stilistik olarak C++ programcıları temel değerleri değerlere göre aktarma eğilimindedir. – vsoftco

+0

Tamam, anlıyorum. Tekrar teşekkürler. Kod yazmak söz konusu olduğunda bilmek ve iyi bir alışkanlık haline getirmek iyidir. –

0

Makrolar çevirmek her şey içinde derleyici tekmeler önce olur Bazen kullanışlı;. ama genel olarak, kaçınılmalıdır. Çünkü çok fazla şey yapabilirsin, ve sonra, hata ayıklayıcısında, neler olduğuna dair hiçbir fikrin yok. Ayrıca

: performans yaklaşımınız iyi olduğunu, naif, dost demek. Öncelikle dili öğrenirsiniz (, modern C++ için serttir, çünkü bir ton önemli kavramlar ve kesinlikle bilmesi ve anlaması gereken şeyler vardır). O zaman pratik yaparsın, pratik yaparsın. Ve sonra, mevcut uygulamanızın performans sorunları yaşadığı bir noktaya geldiğinizde; sonra gerçek sorunu gerçek anlamak için profilleme yapın. Başka bir deyişle

: Performansta ilgileniyorsanız, yanlış soruyu soruyorsunuz. Mimari hakkında (örneğin: potansiyel darboğazlar), konfigürasyon (sisteminizdeki farklı düğümler arasındaki gecikme anlamında) ve benzeri konularda daha fazla endişe etmelisiniz. Tabii ki, sağduyu uygulamanız gerekir; ve bellek veya CPU döngülerini boşa harcayan kod yazmayın. Ancak bazen% 50 daha yavaş çalışan bir kod parçası ... okumak ve sürdürmek için% 500 daha kolay olabilir. Ve eğer yürütme süresi 250ms değil, 500ms ise; Tamamen iyi olabilir (belli bir parçaya dakika başına bin kez denir).

+0

Bu dile hakim olmadığımı ve mümkün olduğunca öğrenmek istediğimin farkındayım. Bu sorunun amacı sadece farklılıkların ne olduğunu anlamaktı, çünkü şu an yazdığım herhangi bir kodu gerçekten geliştirmek istemiyorum, çünkü çok basit. Cevabınız ve ipuçlarınız için teşekkür ederiz. Aslında benim kodumdaki performansı geliştirmeyi düşünmeden önce C++ dünyasında uzun bir yolculuk olacağını anlıyorum. –

0

Makrolar sadece kaynak kodunu değiştirmek için Metin değişikliğini gerçekleştirmek. Bu itibarla

, makrolar doğal kodun performansını etkilemez. Tasarım ve kodda kullandığınız teknikler performansı etkiliyor. Makroların performans üzerindeki tek anlamı, makronun yaptıklarına dayanır (yani, makronun hangi kodu yazacağını yazarsınız).

Makroların büyük tehlikesi, kapsamlarına uymadıklarıdır. Yaptıkları değişiklikler koşulsuz, çapraz işlev sınırları ve bunun gibi şeylerdir. Makroları, amaçlanan şekilde davranmasını sağlamak için (makroda istenmeyen yan etkilerden sakınmak, tanımlanmamış davranışlardan kaçınmak, vb.) Bir sürü incelik vardır. Bu, makroları kullanan kodun anlaşılması daha zor ve doğru olması daha zor olduğu anlamına gelir.

En iyi ihtimalle, modern derleyicilerle, makroları kullanarak elde edebileceğiniz performans artışı, satır içi işlevlerle elde edilebildiği gibi aynıdır - kodun yanlış davranma olasılığının artması pahasına. Bu nedenle, satır içi işlevleri kullanmaktan daha iyidir - makrolardan farklı olarak, bunlar güvenlidir ve diğer kodlarla tutarlı bir şekilde çalışırlar.

Modern derleyiciler, satır içi olarak belirtmiş olsanız bile, bir işlevi satır içi seçmemeyi seçebilir. Böyle bir durumda, genellikle endişelenmenize gerek yok - modern derleyiciler, bir işlevin gerekip gerekmediğine karar vermede modern programcıların çoğundan daha iyi bir iş çıkartabilirler.

+0

Cevabınız için teşekkür ederiz. –

0

Makro ile satır içi bir işlev arasındaki fark, derleyicinin görmeden önce makroyla ilgilenilmesidir.

En iyileştirme bayrakları olmayan derleyicimde (clang ++), kare işlevi satır içinde olmayacak. Bu

4009f0:  55      push %rbp 
4009f1:  48 89 e5    mov %rsp,%rbp 
4009f4:  89 7d fc    mov %edi,-0x4(%rbp) 
4009f7:  8b 7d fc    mov -0x4(%rbp),%edi 
4009fa:  0f af 7d fc    imul -0x4(%rbp),%edi 
4009fe:  89 f8     mov %edi,%eax 
400a00:  5d      pop %rbp 
400a01:  c3      retq 

imul işi yapan montaj talimat gibi oluşturduğu kod dinlenme etrafında veri taşınıyor görünüyor. çağıran kod

gibi
400969:  e8 82 00 00 00   callq 4009f0 <_Z6squarei> 

iI bunu Inline için -O3 bayrağı eklemek görünüyor ve

0000000000400a10 <main>: 
400a10:  41 56     push %r14 
400a12:  53      push %rbx 
400a13:  50      push %rax 
400a14:  48 8b 7e 08    mov 0x8(%rsi),%rdi 
400a18:  31 f6     xor %esi,%esi 
400a1a:  ba 0a 00 00 00   mov $0xa,%edx 
400a1f:  e8 9c fe ff ff   callq 4008c0 <[email protected]> 
400a24:  48 89 c3    mov %rax,%rbx 
400a27:  0f af db    imul %ebx,%ebx 

Bu bir olduğunu imul fonksiyonu C++ kodunda çağrılır ana işlevi gösterir Makineniz için montaj dili üzerinde temel bir tutamaç yapmak ve kaynağınızdaki gcc -S'yi kullanmak için yapmanız gereken makul bir şey ya da tam olarak ne olduğunu görmek için (burada yaptığım gibi) ikili kodunuz. Bu ne yapar:

satır içine fonksiyonunun yerine makro kullanma

0000000000400a10 <main>: 
400a10:  41 56     push %r14 
400a12:  53      push %rbx 
400a13:  50      push %rax 
400a14:  48 8b 7e 08    mov 0x8(%rsi),%rdi 
400a18:  31 f6     xor %esi,%esi 
400a1a:  ba 0a 00 00 00   mov $0xa,%edx 
400a1f:  e8 9c fe ff ff   callq 4008c0 <[email protected]> 
400a24:  48 89 c3    mov %rax,%rbx 
400a27:  0f af db    imul %ebx,%ebx 

Not burada makrolarıyla birçok tehlikelerden biri çok benzer bir şey alır?

x = 5; std::cout << SQUARE(++x) << std::endl; 

36? hayır, 42. 6 olur

std::cout << ++x * ++x << std::endl; 

olur * 7

optimizasyonu umurumda demekle insanlar tarafından ertelendi etmeyin. C veya C++ dilini kendi dilinizde kullanmak kendi başına bir optimizasyon. Sadece onunla zaman harcıyor ve mantıklı olursanız çalışmayı deneyin.

+0

'SQUARE (++ x)' nin gerçek tehlikesi, '36' yerine' 42' üretmemesidir. Tehlike, bir değişkeni tanımlanmamış davranışlar veren tek bir ifadede iki kez değiştirmesidir. '42'yi üretmek yalnızca bir olası sonuçtur. '42' üretebilir, '36' üretebilir, '49' üretebilir veya sabit sürücünüzü yeniden biçimlendirebilir. – Peter

+0

İnsanlar, optimizasyon konusunda endişelenmenize gerek olmadığını söyleyemez. Erken optimizasyonda kendinizi şımartmamanızı söyleyecektir. Bu, gerçek bir ihtiyaç olduğunu bile bilmeden önce optimizasyona düşmemek anlamına gelir. – Peter

+0

Evet, her neyse. Burada çok önemli değil, buradaki nokta "istediğin şeyi yapmayacaksın" Elbette haklısın, -O3'le gcc, 49 verir, clang 42 verir. Her ikisi de -Wall ile kesinlikle güzel bir uyarı verir -Wall ile derleyin Muhtemelen not etmek daha yararlı bir şeydir. – Hal

0

Böyle bir makroyu kullanmak, yalnızca kendi önceliği bir # define'd sabiti ise anlamlıdır, çünkü hesaplama daha sonra önişlemci tarafından gerçekleştirilir. O zaman bile, sonucun beklenen sonuç olduğunu iki kez kontrol edin.

klasik değişkenlere çalışırken

, (inlined) fonksiyonunun olarak tercih edilmelidir: Bu olup

  • yazma-korumalıdır;
  • Bağımsız değişken olarak kullanılan ifadeleri tutarlı bir şekilde ele alır. Bu, sadece Peter tarafından alıntılanan/art arda gelen artışları kapsamakla kalmaz, ama argüman kendi başına bir hesaplama-yoğun ifadesiyle, makro formunu kullanarak bu argümanın değerlendirmesini iki kez zorlar (bu, btw ile aynı değerde değerlendirilemez).) fonksiyon için sadece bir kez.

Görünüşe göre basit işlevlerin hızlı bir şekilde prototiplenmesi için bu tür makroları kodladığımı itiraf etmeliyim, ancak yıllar içinde beni kaybettiren zaman, aklımı değiştirdi!

İlgili konular