C ++ derleyicisi işe yaramaz parantezleri kaldırır / optimize eder mi?


19

Kod olacak mı

int a = ((1 + 2) + 3); // Easy to read

daha yavaş koş

int a = 1 + 2 + 3; // (Barely) Not quite so easy to read

ya da modern derleyiciler "yararsız" parantezleri kaldırmak / optimize etmek için yeterince zekidir.

Çok küçük bir optimizasyon endişesi gibi görünebilir, ancak C # / Java / ... üzerinden C ++ seçmek tamamen optimizasyon (IMHO) ile ilgilidir.


9
Bence C # ve Java bunu da optimize edecek. AST'yi ayrıştırdıklarında ve yarattıklarında, bunun gibi bariz yararsız şeyleri kaldıracaklarına inanıyorum.
Farid Nouri Neshat

5
Okuduğum her şey, JIT derlemesini, zamanın ötesinde derlemeye parası için bir çalışma sağlayan kolayca işaret ediyor, bu yüzden tek başına çok zorlayıcı bir argüman değil. Oyun programlaması getiriyorsunuz - vaktinden önce derlemeyi tercih etmenin gerçek nedeni tahmin edilebilir olmasıdır - JIT derlemesi ile derleyicinin ne zaman başlayacağını ve kod derlemeye başlayacağını asla bilemezsiniz. Ancak, yerel koda vaktinden önce derlemenin çöp toplama ile birbirini
dışlamadığına dikkat çekerim

7
... RAII ve akıllı işaretçilerden daha iyi, bu da bu dillerde oyun programlama yapmanın nispeten okunmamış yoluna karşı iyi dövülmüş yolu (C ++) takip etme meselesi. Parantez hakkında endişelenmenin çılgın olduğunu da not ediyorum - nereden geldiğini görüyorum, ama bu saçma bir mikro optimizasyon. Programınızdaki veri yapılarının ve algoritmaların seçimi kesinlikle bu önemsizliklere değil, performansa hakim olacaktır.
Doval

6
Um ... Tam olarak ne tür bir optimizasyon bekliyorsunuz? Statik analizden bahsediyorsanız, bildiğim çoğu dilde, bunun yerine statik olarak bilinen sonuç gelir (LLVM tabanlı uygulamalar bunu bile zorlar, AFAIK). İcra emri hakkında konuşuyorsanız, aynı işlem olduğu ve yan etkileri olmadığı için önemli değil. Toplama zaten iki işlenen gerektirir. Ve bunu performansla ilgili C ++, Java ve C #'ı karşılaştırmak için kullanıyorsanız, optimizasyonların ne olduğu ve nasıl çalıştığı hakkında net bir fikriniz olmadığı anlaşılıyor, bunun yerine bunu öğrenmeye odaklanmalısınız.
Theodoros Chatzigiannakis

5
Acaba neden a) Eğer parenthesised ifadesi daha okunabilir (Bu yöntemde bu özel düzeni vurgulamak neden sadece yanıltıcı, çirkin görünüyor bana (? Meli o? Burada assiciative olmayabilir) ve aksak) b) Eğer olmadan düşünmek istiyorum neden daha iyi performans gösterme parantez (açıkça parens ayrıştırma olduğunu daha kolay operatör fixities hakkında akla sahip daha bir makine için. As Marc van Leuwen, bu tamamen çalışma zamanı üzerinde hiçbir etkisi yoktur gerçi diyor).
leftaroundabout

Yanıtlar:


87

Derleyici aslında parantez eklemez veya kaldırmaz; sadece ifadenize karşılık gelen bir ayrıştırma ağacı (parantez bulunmayan) oluşturur ve bunu yaparken yazdığınız parantezlere saygı göstermelidir. İfadenizi tamamen parantez içine alırsanız, o zaman ayrıştırıcı ağacın ne olduğu hemen insan okuyucuya açık olacaktır; İçinde olduğu gibi açık bir şekilde parantez koymak aşırıya giderseniz, int a = (((0)));o zaman ortaya çıkan ayrıştırma ağacını (ve dolayısıyla üretilen kodu değiştirmeden) ayrıştırıcıda bazı döngüleri harcarken, okuyucunun nöronları üzerinde bazı gereksiz strese neden olacaksınız. ) en ufak bir parça.

Eğer varsa yok herhangi parantez yazma, ayrıştırıcı hala çözümleme ağacı yaratma işini gerekir ve operatör önceliği ve çağrışımsal kuralları tam olarak o Yapı, gereken ayrıştırma ağacı söyle. Bu kuralları derleyiciye kodunuza hangi (örtülü) parantezleri eklemesi gerektiğini söyleyebilirsiniz , ancak bu durumda ayrıştırıcı aslında parantezle ilgilenmez: parantez gibi aynı ayrıştırma ağacını üretmek için oluşturulmuştur. bazı yerlerde vardı. Parantezleri tam olarak bu yerlere yerleştirirseniz int a = (1+2)+3;( olduğu gibi ( +sola olan ilişkisi ), ayrıştırıcı biraz farklı bir yolla aynı sonuca ulaşacaktır. Farklı parantezlerint a = 1+(2+3);farklı bir ayrıştırma ağacını zorlarsınız, bu da muhtemelen farklı kodların üretilmesine neden olur (belki de olmasa da, derleyici ayrıştırma ağacını oluşturduktan sonra dönüşümler uygulayabildiği için, sonuçta ortaya çıkan kodu yürütmenin etkisi hiçbir zaman farklı olmaz o). Sonuç kodunda bir fark olduğunu varsayarsak, genel olarak hiçbir şeyin hangisinin daha verimli olduğu söylenemez; en önemli nokta, elbette, ayrıştırma ağaçlarının çoğu zaman matematiksel olarak eşdeğer ifadeler vermemesidir, bu yüzden yürütme hızlarını karşılaştırmak noktanın yanındadır: kişi sadece doğru sonucu veren ifadeyi yazmalıdır.

Sonuç olarak: doğruluk için gerektiğinde ve okunabilirlik için istendiği gibi parantez kullanın; gereksizse, yürütme hızı üzerinde hiçbir etkisi yoktur (ve derleme zamanı üzerinde ihmal edilebilir bir etkisi vardır).

Ve bunların hiçbirinin , ayrıştırma ağacı yapıldıktan sonra ortaya çıkan optimizasyon ile ilgisi yoktur , bu nedenle ayrıştırma ağacının nasıl inşa edildiğini bilemez. Bu, en eski ve en aptal derleyiciden en akıllı ve en modern derleyicilere değişmeden uygulanır. Sadece yorumlanmış bir dilde ("derleme zamanı" ve "yürütme zamanı" çakışıyorsa) gereksiz parantezler için bir ceza olabilir, ancak o zaman bile bu tür dillerin çoğunun en azından ayrıştırma aşamasının yalnızca bir kez yapılması için organize edildiğini düşünüyorum her ifade için (yürütme için önceden ayrıştırılmış bazı formlarını saklamak).


s / oldes / eski /. Güzel cevap +1.
David Conrad

23
Toplam nitpick uyarısı: "Soru çok iyi konulmamış." - Katılıyorum, "iyi koymak" demek için "querent'in hangi bilgi boşluğunun doldurulmasını istediği açıkça belirtiliyor". Aslında soru "X için optimize etmek, A veya B'yi seçmek ve neden? Altında ne olur?". Bu da en azından benim için bilgi boşluğunun ne olduğunu açıkça ortaya koyuyor. Haklı olarak iyi bir şekilde işaret ettiğiniz ve ele aldığınız sorudaki kusur, hatalı bir zihinsel model üzerine inşa edilmiş olmasıdır.
Jonas Kölker

İçin a = b + c * d;, a = b + (c * d);olacaktır [zararsız] gereksiz parantez. Kodu daha okunabilir hale getirmenize yardımcı olurlarsa, iyi. a = (b + c) * d;gereksiz parantez olur - sonuçta elde edilen ayrıştırma ağacını değiştirir ve farklı bir sonuç verir. Tamamen yasal (aslında gerekli), ancak ima edilen varsayılan gruplama ile aynı değildir.
Phil Perry

1
@OrangeDog doğru, utanç verici Ben'in yorumu VM'lerin yerelden daha hızlı olduğunu iddia eden birkaç kişiyi ortaya çıkardı.
gbjbaanb

1
@ JonasKölker: Açılış cümlemim aslında başlıkta formüle edilen soruyu ifade ediyor: derleyicinin parantez ekleyip çıkarmayacağı hakkındaki bir soruya gerçekten cevap verilemiyor, çünkü bu derleyicilerin nasıl çalıştığına dair yanlış bir anlayışa dayanıyor. Ancak, hangi bilgi boşluğunun ele alınması gerektiğinin oldukça açık olduğunu kabul ediyorum.
Marc van Leeuwen

46

Parantezler derleyicilerin değil sadece sizin yararınadır. Derleyici, ifadenizi temsil etmek için doğru makine kodunu oluşturur.

FYI, derleyici eğer mümkünse tamamen optimize edebilecek kadar zekidir. Örneklerinizde, bu int a = 6;derleme zamanında dönüşür .


9
Kesinlikle - istediğiniz kadar parantez içinde sopa ve derleyici ne istediğinizi bulmak zor iş
yapalım

23
@Serge true programlama, kodunuzun okunabilirliği ve performanstan çok daha fazlasıdır. Önümüzdeki yıl bir kilitlenmeyi ayıklamanız gerektiğinde kendinizden nefret edeceksiniz ve sadece "optimize edilmiş" kodunuz var.
cırcır ucube

1
@ratchetfreak, haklısın henüz kodumu nasıl yorumlayacağımı da biliyorum. int a = 6; // = (1 + 2) + 3
Serge

20
@Serge Bir yıl süren değişikliklerden sonra dayanamayacağını biliyorum, zaman içinde yorumlar ve kod senkronizasyondan çıkacak ve sonraint a = 8;// = 2*3 + 5
cırcır ucube

21
veya www.thedailywtf.com int five = 7; //HR made us change this to six...
adresinden

23

Aslında sorduğunuz sorunun cevabı hayırdır, ancak sormak istediğiniz sorunun cevabı evettir. Parantez eklemek kodu yavaşlatmaz.

Optimizasyon hakkında bir soru sordunuz, ancak parantezlerin optimizasyonla ilgisi yok. Derleyici, oluşturulan kodun boyutunu veya hızını (bazen her ikisini de) geliştirmek amacıyla çeşitli optimizasyon teknikleri uygular. Örneğin, A ^ 2 (A kare) ifadesini alabilir ve daha hızlıysa, A x A (A ile çarpılır) ile değiştirebilir. Buradaki cevap hayırdır, derleyici, parantezlerin bulunup bulunmamasına bağlı olarak optimizasyon aşamasında farklı bir şey yapmaz.

Bence bir ifadeye gereksiz parantez eklerseniz okunabilirliği artırabileceğini düşündüğünüz yerlerde derleyicinin aynı kodu üretip üretmediğini sormak istediniz. Başka bir deyişle, parantez eklerseniz, bir şekilde daha kötü kod üretmek yerine, onları çıkarmaya yetecek kadar akıllı derleyicidir. Cevap her zaman evet.

Bunu dikkatlice söyleyeyim. Kesinlikle gereksiz olan bir ifadeye parantez eklerseniz (bir ifadenin anlamı veya değerlendirme sırası üzerinde hiçbir etkisi yoktur) derleyici bunları sessizce atar ve aynı kodu oluşturur.

Bununla birlikte, görünüşte gereksiz parantezlerin bir ifadenin değerlendirme sırasını gerçekten değiştireceği ve bu durumda derleyicinin gerçekte yazdıklarınızı yürürlüğe koymak için, istediğinizden farklı olabilecek kod üreteceği belirli ifadeler vardır. İşte bir örnek. Bunu yapma!

short int a = 30001, b = 30002, c = 30003;
int d = -a + b + c;    // ok
int d = (-a + b) + c;  // ok, same code
int d = (-a + b + c);  // ok, same code
int d = ((((-a + b)) + c));  // ok, same code
int d = -a + (b + c);  // undefined behaviour, different code

İsterseniz parantez ekleyin, ancak gerçekten gereksiz olduklarından emin olun!

Asla yapmam. Gerçek bir fayda olmadan hata riski vardır.


Dipnot: imzasız davranış, işaretli bir tamsayı ifadesi ifade edebileceği aralığın dışında bir değer olarak değerlendirildiğinde oluşur, bu durumda -32767 ila +32767. Bu, bu cevabın kapsamı dışında, karmaşık bir konudur.


Son satırda tanımlanmamış davranış, işaretli bir kısa işaretten sonra sadece 15 bit olması, yani maksimum 32767 boyutu, değil mi? Bu önemsiz örnekte, derleyici taşma konusunda uyarmalıdır, değil mi? Her iki şekilde de karşı örnek için +1. Eğer bir fonksiyonun parametreleri olsaydı, bir uyarı alamazsınız. Ayrıca, agerçekten imzasız -a + bolabilirse , hesaplamanıza liderlik etmek a, negatif ve bpozitif olsaydı da kolayca taşabilir .
Patrick M

@PatrickM: düzenlemeye bakın. Tanımsız davranış, derleyicinin uyarı vermek de dahil olmak üzere sevdiği şeyi yapabileceği anlamına gelir. İmzasız aritmetik UB üretmez, ancak bir sonraki yüksek güç modülo azalır.
david.pfx

(b+c)Son satırdaki ifade argümanlarını destekleyecektir int, bu yüzden derleyici int16 bit olarak tanımlanmadıkça (ya eski ya da küçük bir mikro denetleyiciyi hedeflediği için) son satır son derece meşru olacaktır.
supercat

@supercat: Sanmıyorum. Sonucun ortak türü ve türü kısa int olmalıdır. Bu hiç sorulmamış bir şey değilse, belki bir soru göndermek istersiniz?
david.pfx

@ david.pfx: C aritmetik promosyonlarının kuralları oldukça açıktır: bu tür, tüm değerleri temsil edemeyeceği sürece inttanıtıldığından daha küçük olan her şey inttanıtılır unsigned int. Tüm tanımlanmış davranışlar, tanıtımların dahil edilmesiyle aynı olursa derleyiciler tanıtımları atlayabilir . 16 bitlik tiplerin bir sargı soyut cebir halkası gibi davrandığı bir makinede, (a + b) + c ve a + (b + c) eşdeğer olacaktır. Eğer inttaşma mahsur kalan bir 16 bit türü vardı, ancak, daha sonra durumlar nerede olacağını ifadelerden birinin ...
SuperCat

7

Köşeli parantezler yalnızca işleç önceliği sırasını değiştirmeniz içindir. Derlendiğinde, çalışma zamanının bunlara ihtiyacı olmadığı için köşeli parantezler artık mevcut değildir. Derleme işlemi, sizin ve benim ihtiyaç duyduğumuz tüm parantezleri, boşlukları ve diğer sözdizimsel şekeri kaldırır ve tüm operatörleri bilgisayarın yürütmesi için çok daha basit bir şeye dönüştürür.

Yani, sen ve ben nerede görebiliriz ...

  • "int a = ((1 + 2) + 3);"

... derleyici böyle bir şey yayabilir:

  • Char [1] :: "a"
  • Int32 :: DeclareStackVariable ()
  • Int32 :: 0x00000001
  • Int32 :: 0x00000002
  • Int32 :: Add ()
  • Int32 :: 0x00000003
  • Int32 :: Add ()
  • Int32 :: AssignToVariable ()
  • void :: DiscardResult ()

Program başlangıçta başlatılarak ve her komutun sırayla yürütülmesi ile yürütülür.
Operatör önceliği şimdi "ilk gelen, ilk servis edilir".
Derleyici tüm yaradıkları için her şey şiddetle yazıldığında o da ayrı özgün sözdizimi yırtılma iken dışarı.

Tamam, bu sizin ve benim uğraştığımız şeylere benzemiyor, ama sonra çalıştırmıyoruz!


4
Böyle bir şeyi uzaktan bile üretecek tek bir C ++ derleyicisi yoktur. Genellikle gerçek CPU kodu üretir ve montaj da bu görünmez.
MSalters

3
buradaki amaç, yazılı kod ile derlenmiş çıktı arasındaki yapı farkını göstermekti. burada bile çoğu insan gerçek makine kodunu veya montajını
okuyamaz

@ MSalters Nitvicking clang, LLVM ISA'ya 'böyle bir şey' olarak davranırsanız ('SSA yığın tabanlı değil)' böyle bir şey yayar. LLVM ve JVM ISA (AFAIK) için JVM arka ucu yazmanın mümkün olduğu göz önüne alındığında, yığın tabanlı clang-> llvm-> JVM çok benzer görünecektir.
Maciej Piechotka

LLVM ISA, çalışma zamanı dizesi değişmezlerini (yalnızca ilk iki yönerge) kullanarak ad yığını değişkenleri tanımlama yeteneğine sahip olduğunu sanmıyorum. Bu, çalışma zamanı ve derleme süresini ciddi şekilde karıştırmaktadır. Ayrım önemlidir çünkü bu soru tam olarak bu karışıklıkla ilgilidir.
MSalters

6

Kayan nokta olup olmadığına bağlıdır:

  • Kayan noktalı aritmetik toplama ilişkilendirici değildir, bu nedenle optimizer işlemleri yeniden sıralayamaz (fastmath derleyici anahtarını eklemediğiniz sürece).

  • Tamsayı işlemlerinde yeniden sıralanabilirler.

Örneğinizde her ikisi de aynı zamanı çalıştıracaktır çünkü aynı kodla derleneceklerdir (toplama soldan sağa değerlendirilmiştir).

java ve C # bile onu optimize edebilecek, sadece çalışma zamanında yapacaklar.


Kayan nokta işlemlerinin ilişkilendirici olmadığını göstermek için +1.
Doval

Soru örneğinde, parantezler varsayılan (sol) ilişkilendirmeyi değiştirmez, bu nedenle bu nokta tartışmalıdır.
Marc van Leeuwen

1
Son cümle hakkında sanmıyorum. Hem java a hem de c # 'da derleyici optimize edilmiş bayt kodu / IL üretecektir. Çalışma zamanı etkilenmez.
Stefano Altieri

IL bu tür ifadelerde çalışmaz, talimatlar bir yığından belirli sayıda değer alır ve yığına belirli sayıda değer (genellikle 0 veya 1) döndürür. C # 'da çalışma zamanında optimize edilmiş bu tür şeylerden bahsetmek saçmadır.
Jon Hanna

6

Tipik C ++ derleyicisi, C ++ 'ın kendisine değil, makine koduna çevirir . İşe yaramaz parensleri kaldırır, evet, çünkü bittiğinde, hiç parens yoktur. Makine kodu bu şekilde çalışmıyor.



1

Hayır, ama evet, ama belki, ama belki başka bir yol, ama hayır.

İnsanların daha önce işaret ettiği gibi, (eklemenin C, C ++, C # veya Java gibi sol ilişkisel olduğu bir dil varsayarsak) ifadenin ((1 + 2) + 3)tam olarak eşdeğerdir 1 + 2 + 3. Kaynak kodda, sonuçtaki makine kodu veya bayt kodu üzerinde sıfır etkisi olacak bir şey yazmanın farklı yollarıdır.

Her iki durumda da sonuç, örneğin iki kayıt eklemek ve daha sonra bir üçüncü eklemek veya bir yığından iki değer almak, eklemek, geri itmek, sonra diğerini almak ve eklemek ya da üç kayıt eklemek için bir talimat olacaktır. tek bir işlem veya bir sonraki düzeyde neyin en duyarlı olduğuna bağlı olarak üç sayıyı toplamak için başka bir yol (makine kodu veya bayt kodu). Bayt kodu durumunda, bu muhtemelen benzer bir yeniden yapılandırmaya tabi tutulacaktır, örneğin bunun IL eşdeğeri (bir yığına bir dizi yük olacak ve sonucu eklemek ve sonra geri itmek için haşhaş çiftleri olacaktır) bu mantığın makine kodu düzeyinde doğrudan bir kopyasıyla sonuçlanmaz, ancak söz konusu makine için daha mantıklı bir şeyle sonuçlanır.

Ama sorunuzda daha fazlası var.

Herhangi bir aklı başında C, C ++, Java veya C # derleyicisi olması durumunda, verdiğiniz ifadelerin her ikisinin sonucunun tam olarak aynı sonuçlara sahip olmasını beklerim:

int a = 6;

Sonuçta ortaya çıkan kod neden hazır bilgi üzerinde matematik yapmak için zaman kaybetmeli? Programın durumunda hiçbir değişiklik 1 + 2 + 3olmanın sonucunu durduramaz 6, bu yüzden yürütülmekte olan kodda ne olması gerekir. Gerçekten de, belki de (bu 6 ile ne yaptığınıza bağlı olarak, belki de her şeyi atabiliriz) ve C # felsefesi ile "yoğun bir şekilde optimize etmeyin, çünkü yine de jitter bunu optimize edecektir" eşdeğeri int a = 6ya da sadece gereksiz her şeyi atmak).

Yine de bu bizi sorunuzun olası bir uzantısına götürür. Aşağıdakileri göz önünde bulundur:

int a = (b - 2) / 2;
/* or */
int a = (b / 2)--;

ve

int c;
if(d < 100)
  c = 0;
else
  c = d * 31;
/* or */
int c = d < 100 ? 0 : d * 32 - d
/* or */
int c = d < 100 && d * 32 - d;
/* or */
int c = (d < 100) * (d * 32 - d);

(Bu son iki örnek geçerli C # değildir, burada her şey geçerlidir ve C, C ++ ve Java için geçerlidir.)

Burada yine çıktı açısından tam olarak eşdeğer bir kod var. Sabit ifadeler olmadıkları için derleme zamanında hesaplanmazlar. Bir formun diğerinden daha hızlı olması mümkündür. Hangisi daha hızlı? Bu işlemciye ve belki de durumdaki bazı keyfi farklılıklara bağlı olacaktır (özellikle biri daha hızlıysa, çok daha hızlı olması muhtemel değildir).

Ve bunlar, çoğunlukla bir şeyin kavramsal olarak yapıldığı sıradaki farklarla ilgili olduğu için, sorunuzla tamamen alakasız değildir .

Her birinde, birinin diğerinden daha hızlı olabileceğinden şüphelenmek için bir neden var. Tek düşüşlerin özel bir talimatı (b / 2)--olabilir , bu yüzden gerçekten daha hızlı olabilir (b - 2) / 2. d * 32belki daha hızlı dönüştürerek üretilen olabilir d << 5yapım böylece d * 32 - ddaha hızlı d * 31. Son ikisi arasındaki farklar özellikle ilginçtir; bir tanesi bazı durumlarda bazı işlemlerin atlanmasına izin verirken diğeri dalın yanlış tahmin olasılığını ortadan kaldırır.

Yani, bu bize iki soru bırakıyor: 1. Biri diğerinden daha hızlı mı? 2. Bir derleyici daha yavaş olanı daha hızlıya çevirir mi?

Ve cevap 1'dir. 2. Belki.

Veya genişletmek için, söz konusu işlemciye bağlı olduğu için bağlıdır. Kuşkusuz, birinin saf makine kodu eşdeğerinin diğerinin saf makine kodu eşdeğerinden daha hızlı olacağı işlemciler vardır. Elektronik bilgi işlem tarihi boyunca, her zaman daha hızlı olan bir tane de yoktu (özellikle dal yanlış tahmin öğesi, boru hattı olmayan CPU'lar daha yaygın olduğunda birçok kişi için geçerli değildi).

Ve belki de, derleyicilerin (ve titremelerin ve komut dosyası motorlarının) yapacağı bir dizi farklı optimizasyon olduğundan ve bazıları belirli durumlarda zorunlu kılınsa da, genellikle mantıksal olarak eşdeğer bazı kod parçaları bulabiliriz. en saf derleyici bile tam olarak aynı sonuçlara ve mantıksal olarak eşdeğer bazı kodlara sahiptir, burada en sofistike olanlar bile diğerine göre daha hızlı kod üretir (sadece amacımızı kanıtlamak için tamamen patolojik bir şey yazsak bile).

Çok küçük bir optimizasyon endişesi gibi görünebilir,

Hayır. Burada verdiğimden daha karmaşık farklılıklarla bile, optimizasyonla ilgisi olmayan kesinlikle küçük bir endişe gibi görünüyor. Eğer bir şey varsa, bu bir karamsarlık meselesidir, çünkü okumamanın daha zor olması, okunması ((1 + 2) + 3daha kolay olandan daha yavaş olabilir 1 + 2 + 3.

ancak C # / Java / ... üzerinden C ++ seçimi tamamen optimizasyon (IMHO) ile ilgilidir.

C # veya Java üzerinden C ++ seçmenin "hepsi hakkında" olması buysa, insanların Stroustrup ve ISO / IEC 14882 kopyalarını yazmaları ve C ++ derleyicilerinin alanlarını boşaltmaları ve daha fazla MP3 veya başka bir şey için yer bırakmaları gerektiğini söyleyebilirim.

Bu diller birbirinden farklı avantajlara sahiptir.

Bunlardan biri, C ++ 'ın bellek kullanımında hala daha hızlı ve daha hafif olmasıdır. Evet, C # ve / veya Java'nın daha hızlı olduğu ve / veya uygulama ömrü boyunca bellek kullanımının daha iyi olduğu örnekler vardır ve bunlar ilgili teknolojiler geliştikçe daha yaygın hale gelir, ancak yine de C ++ ile yazılmış ortalama programın işini daha hızlı yapan ve bu iki dilde eşdeğerden daha az bellek kullanan daha küçük bir yürütülebilir dosya.

Bu bir optimizasyon değil.

Optimizasyon bazen "işleri hızlandırmak" için kullanılır. Bu anlaşılabilir bir durumdur, çünkü çoğu zaman gerçekten "optimizasyon" dan bahsettiğimizde, gerçekten işleri daha hızlı hale getirmekten bahsediyoruz ve bu yüzden biri diğeri için bir kısayol haline geldi ve kelimeyi kendim bu şekilde kötüye kullandığımı itiraf edeceğim.

"İşleri daha hızlı hale getirmek" için doğru kelime optimizasyon değildir . Buradaki doğru kelime iyileştirmedir . Bir programda değişiklik yaparsanız ve tek anlamlı fark, artık daha hızlı olması, hiçbir şekilde optimize edilmemesi, sadece daha iyi olmasıdır.

Optimizasyon , belirli bir yön ve / veya özel durumla ilgili bir iyileştirme yaptığımız zamandır. Ortak örnekler:

  1. Artık bir kullanım durumu için daha hızlı, diğeri için daha yavaş.
  2. Şimdi daha hızlı, ancak daha fazla bellek kullanıyor.
  3. Artık bellekte daha hafif, ancak daha yavaş.
  4. Şimdi daha hızlı, ancak bakımı daha zor.
  5. Artık bakımı daha kolay, ancak daha yavaş.

Bu gibi durumlar, örneğin:

  1. Daha hızlı kullanım durumu, daha yaygın veya daha ciddi şekilde engellenir.
  2. Program kabul edilemez derecede yavaştı ve çok fazla RAM kullanmıyoruz.
  3. Program durma noktasına geliyordu, çünkü çok fazla RAM kullandı, süper hızlı işlemesini gerçekleştirmekten daha fazla zaman harcadı.
  4. Program kabul edilemez derecede yavaştı ve kodun anlaşılması daha iyi belgelenmiş ve nispeten kararlı.
  5. Program hala kabul edilebilir derecede hızlıdır ve daha anlaşılır kod tabanının bakımı daha ucuzdur ve diğer geliştirmelerin daha kolay yapılmasına izin verir.

Ancak, bu gibi durumlar diğer senaryolarda da haklı görülmeyecektir: Kod, mutlak yanılmaz bir kalite ölçüsü ile daha iyi hale getirilmemiştir, belirli bir kullanım için daha uygun hale getiren belirli bir açıdan daha iyi hale getirilmiştir; Optimize edilmiş.

Ve burada dil seçiminin bir etkisi var, çünkü hız, bellek kullanımı ve okunabilirlik bundan etkilenebilir, ancak diğer sistemlerle uyumluluk, kütüphanelerin kullanılabilirliği, çalışma zamanlarının kullanılabilirliği, belirli bir işletim sisteminde bu çalışma zamanlarının olgunluğu da olabilir (günahlarım için bir şekilde en sevdiğim işletim sistemleri olarak Linux ve Android'e ve en sevdiğim dil olarak C # 'a sahip oldum ve Mono harika olsa da, yine de buna karşı geliyorum).

"C # / Java / ... üzerinden C ++ seçimi tüm optimizasyonlarla ilgilidir" demek sadece C ++ 'ın gerçekten berbat olduğunu düşünüyorsanız mantıklıdır, çünkü optimizasyon "daha iyi ..." değil, "daha iyi" değil. C ++ 'ın kendisine rağmen daha iyi olduğunu düşünüyorsanız, ihtiyacınız olan son şey mümkün olan en kısa mikro-seçimler hakkında endişelenmektir. Gerçekten de, muhtemelen onu terk etmekten daha iyidir; mutlu hackerlar da optimize etmek için bir kalite!

Bununla birlikte, "C ++ 'ı seviyorum ve bununla ilgili sevdiğim şeylerden biri ekstra döngüleri sıkmak" demeye meyilliyseniz, bu farklı bir konudur. Hala mikro-ops'ların sadece refleksif bir alışkanlık olabilmeleri durumunda buna değer olduğu bir durumdur (yani, doğal olarak kodlama eğiliminiz yavaş olandan daha hızlı olacaktır). Aksi takdirde erken optimizasyon bile değiller, işleri daha da kötüleştiren erken karamsarlık.


0

Parantezler derleyiciye hangi sıra ifadelerinin değerlendirilmesi gerektiğini söylemek için vardır. Bazen işe yaramazlar (okunabilirliği geliştirmeleri veya kötüleşmeleri dışında), çünkü yine de kullanılacak düzeni belirtirler. Bazen düzeni değiştirirler. İçinde

int a = 1 + 2 + 3;

pratikte var olan her dil toplamın 1 + 2 ve ardından sonuç artı 3 eklenerek değerlendirilme kuralına sahiptir.

int a = 1 + (2 + 3);

parantez farklı bir sıraya girer: Önce 2 + 3 ekler, sonra 1 artı sonuç ekler. Parantez örneğiniz zaten üretilenle aynı sırayı verir. Şimdi bu örnekte, işlemlerin sırası biraz farklıdır, ancak tamsayı eklemenin çalışma şekli, sonuç aynıdır. İçinde

int a = 10 - (5 - 4);

parantezler kritiktir; onları dışarıda bırakmak sonucu 9'dan 1'e değiştirir.

Derleyici hangi işlemlerin hangi sırayla gerçekleştirildiğini belirledikten sonra, parantez tamamen unutulur. Derleyicinin bu noktada hatırladığı tek şey hangi işlemlerin hangi sırayla yapılacağıdır. Yani derleyicinin burada optimize edebileceği hiçbir şey yok, parantez yok .


practically every language in existence; APL hariç: (burada) [tryapl.org] (1-2)+3(2), 1-(2+3)(-4) ve 1-2+3(ayrıca -4) ifadelerini girmeyi deneyin .
14'te tomsmeding

0

Bununla birlikte, söylenenlerin çoğuna katılıyorum… buradaki üst kemer, parantezlerin çalışma düzenini zorlamak için orada olduğu… derleyicinin kesinlikle yaptığı. Evet, makine kodu üretiyor… ama mesele bu değil ve sorulan şey bu değil.

Parantezler gerçekten gitti: söylendiği gibi, bunlar makine kodunun bir parçası değil, sayılar ve başka bir şey değil. Montaj kodu makine kodu değildir, yarı insan tarafından okunabilir ve talimatları adla içerir - opcode değil. Makine opcode adı verileni çalıştırır - montaj dilinin sayısal gösterimleri.

Java gibi diller, bunları üreten makinede yalnızca kısmen derlendikçe aradaki bir alana düşer. Onları çalıştıran makinede makineye özel kod için derlenirler, ancak bu soru için bir fark yaratmaz - parantezler ilk derlemeden sonra hala gider.


1
Bunun soruyu cevapladığından emin değilim. Destekleyici paragraflar yardımcı olmaktan daha kafa karıştırıcıdır. Java derleyicisi C ++ derleyicisiyle nasıl ilişkilidir?
Adam Zuckerman

OP parantezin gidip gitmediğini sordu… Ben de söyledim ve yürütülebilir kodun sadece opcodları temsil eden sayılar olduğunu açıkladım. Java başka bir cevapta ortaya çıktı. Bence soruyu gayet iyi cevaplıyor… ama bu sadece benim düşüncem. Cevabınız için teşekkürler.
jinzai

3
Parantezler "operasyon sırasını" zorlamaz. Önceliği değiştirirler. Yani, içinde a = f() + (g() + h());derleyici ücretsiz, aramak f, gve hbu sırayla (veya herhangi bir sırada o hoşnut).
Alok

Bu ifadeyle bazı anlaşmazlıklarım var… kesinlikle operasyon sırasını parantez içinde zorlayabilirsiniz.
jinzai

0

Derleyiciler dilden bağımsız olarak tüm infix matematiğini postfix'e çevirir. Başka bir deyişle, derleyici aşağıdaki gibi bir şey gördüğünde:

((a+b)+c)

bunu şuna çevirir:

 a b + c +

Bu, infix gösteriminin okunması daha kolay olsa da, postfix gösterimi bilgisayarın işi yapmak için atması gereken gerçek adımlara çok daha yakın olduğu için (ve bunun için zaten iyi geliştirilmiş bir algoritma olduğu için). postfix, işlem sırasına veya parantezle ilgili tüm sorunları ortadan kaldırır, bu da aslında makine kodunu yazarken işleri daha kolay hale getirir.

Konu hakkında daha fazla bilgi için Reverse Polish Notation hakkındaki wikipedia makalesini öneriyorum .


5
Bu, derleyicilerin işlemleri nasıl çevirdiğine dair yanlış bir varsayımdır. Örneğin, burada bir yığın makinesi olduğunu varsayıyorsunuz. Bir vektör işlemciniz olsaydı ne olurdu? ya çok miktarda sicile sahip bir makineniz olsaydı?
Ahmed Mesud
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.