C'de i ++ ve ++ i arasında bir performans farkı var mı?


Yanıtlar:


396

Yönetici özeti: Hayır.

i++++ieski değerinin i daha sonra kullanılmak üzere kaydedilmesi gerekebileceğinden potansiyel olarak daha yavaş olabilir, ancak pratikte tüm modern derleyiciler bunu optimize edecektir.

Bunu hem ++ive hem de bu işlevin koduna bakarak gösterebiliriz i++.

$ cat i++.c
extern void g(int i);
void f()
{
    int i;

    for (i = 0; i < 100; i++)
        g(i);

}

Dosyalar ++ive dışında aynıdır i++:

$ diff i++.c ++i.c
6c6
<     for (i = 0; i < 100; i++)
---
>     for (i = 0; i < 100; ++i)

Onları derleyeceğiz ve oluşturulan derleyiciyi de alacağız:

$ gcc -c i++.c ++i.c
$ gcc -S i++.c ++i.c

Hem üretilen nesne hem de birleştirici dosyalarının aynı olduğunu görebiliriz.

$ md5 i++.s ++i.s
MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e
MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e

$ md5 *.o
MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22
MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22

9
Bu sorunun C ile ilgili olduğunu biliyorum, ancak tarayıcıların javascript için bu optimizasyonu yapıp yapamayacağını bilmek isterim.
TM.

69
Yani "Hayır", test ettiğiniz derleyici için geçerlidir.
Andreas

173
@Andreas: Güzel soru. Derleyici yazarıydım ve bu kodu birçok CPU, işletim sistemi ve derleyicide test etme fırsatım oldu. İ ++ kasasını optimize etmediğini bulduğum tek derleyici (aslında, bunu profesyonel olarak dikkatime çeken derleyici) Walt Bilofsky'nin Software Toolworks C80 derleyicisiydi. Bu derleyici Intel 8080 CP / M sistemleri içindi. Bu optimizasyonu içermeyen herhangi bir derleyicinin genel kullanım amaçlı olmadığı söylenebilir.
Mark Harrison

22
Performans farkı göz ardı edilebilir ve birçok durumda optimize edilmiş olsa da, lütfen ++ibunun yerine hala iyi bir uygulama olduğunu unutmayın i++. Kesin olmamak için hiçbir neden yoktur ve yazılımınız onu optimize etmeyen bir araç zincirinden geçerse, yazılımınız daha verimli olacaktır. Bunu göz önünde bulundurarak sadece kadar kolay yazmaktır ++iyazmanın ne kadar i++, kullanmıyor olması için hiçbir bahane gerçekten yoktur ++iilk etapta.
monokrome

7
@monokrome Geliştiriciler, birçok dilde önek ve son düzeltme işleçleri için kendi uygulamalarını sağlayabildiğinden, bu, bir derleyicinin, önemsiz olabilecek ilk işlevleri karşılaştırmadan yapması her zaman kabul edilebilir bir çözüm olmayabilir.
pickypg

112

Gönderen niyet karşısında Verimlilik Andrew Koenig tarafından:

Birincisi, en azından tamsayı değişkenleri söz konusu olduğunda ++idaha etkili olduğu açıktır i++.

Ve :

Yani sorulması gereken soru, bu iki işlemden hangisinin daha hızlı olduğu değil, bu iki işlemden hangisini gerçekleştirmeye çalıştığınızı daha doğru bir şekilde ifade etmesidir. İfadenin değerini kullanmıyorsanız, i++bunun yerine kullanmak ++iiçin asla bir neden olmadığını, çünkü bir değişkenin değerini kopyalamak, değişkeni artırmak ve daha sonra kopyayı atmak için hiçbir neden olmadığına inanıyorum .

Yani, sonuçta ortaya çıkan değer kullanılmazsa, kullanırım ++i. Ama daha verimli olduğu için değil: çünkü niyetimi doğru bir şekilde ifade ediyor.


5
Unutmayalım ki diğer tekli operatörler de önektir. I + + belirli bir ihtiyaca (ek önce değerlendirme) sığdırmak için etrafında iken, i + tek bir operatör kullanmak için "anlamsal" bir yol olduğunu düşünüyorum.
TM.

9
Ortaya çıkan değer kullanılmazsa, anlambilimde bir fark yoktur : yani, birini veya diğerini tercih etmek için bir temel yoktur.
Eamon Nerbonne

3
Okuyucu olarak bir fark görüyorum. Bir yazar olarak, niyetimi birini diğerinden seçerek göstereceğim. Bu sadece bir alışkanlık, programcı arkadaşlarım ve takım arkadaşlarımla kod aracılığıyla iletişim kurmaya çalışmak :)
Sébastien RoccaSerra

11
Koenig 'tavsiyelerine uyarak kod i++aynı şekilde ben kod olur i += nveya i = i + nbiçim içinde, yani hedefin fiil nesne ile, hedefin işlenen sol için fiil operatörü. Durumda, i++doğru nesne yoktur , ancak hedef fiil operatörünün solunda tutularak kural geçerlidir .
David R Tribble

4
Eğer i'yi artırmaya çalışıyorsanız, i ++ ve ++ i'nin ikisi de niyetinizi doğru ifade eder. Birini diğerine tercih etmek için hiçbir sebep yok. Bir okuyucu olarak hiçbir fark görmüyorum, meslektaşlarınız i ++ gördüklerinde kafaları karışıyor mu?
dan carter

46

Daha iyi bir cevap, ++ibazen daha hızlı olacak ama asla daha yavaş olmayacak.

Herkes ibunun normal yerleşik bir tür olduğunu varsayıyor gibi görünüyor int. Bu durumda ölçülebilir bir fark olmayacaktır.

Ancak ikarmaşık tip ise , ölçülebilir bir fark bulabilirsiniz. Çünkü i++artırmadan önce sınıfınızın bir kopyasını oluşturmanız gerekir. Bir kopyaya neyin dahil olduğuna bağlı olarak, gerçekten daha yavaş olabilir, çünkü ++itsadece son değeri iade edebilirsiniz.

Foo Foo::operator++()
{
  Foo oldFoo = *this; // copy existing value - could be slow
  // yadda yadda, do increment
  return oldFoo;
}

Başka bir fark, ++isizinle birlikte bir değer yerine bir referans döndürme seçeneğiniz olmasıdır. Yine, nesnenizin bir kopyasını oluşturmaya neyin bağlı olduğuna bağlı olarak, bu daha yavaş olabilir.

Bunun gerçekleşebileceği gerçek dünya örneği yineleyicilerin kullanımı olacaktır. Bir yineleyiciyi kopyalamanın uygulamanızda bir şişe boynu olması muhtemel değildir, ancak sonucun etkilenmediği yer ++iyerine kullanma alışkanlığına girmek hala iyi bir uygulamadır i++.


36
Soru C'yi açıkça belirtmektedir, C ++ referansı yoktur.
Dan Cristoloveanu

5
Bu (kuşkusuz eski) soru C ++ ile ilgili değildi, ancak C ++ 'da, bir sınıfın post ve fix öncesi operatörleri uygulasa bile, bunların ille de ilişkili olmadıklarını da belirtmek gerekir. Örneğin, bar ++ bir veri üyesini artırabilirken ++ bar farklı bir veri üyesini artırabilir ve bu durumda anlambilim farklı olduğundan ikisini de kullanma seçeneğiniz olmaz.
Kevin

-1 Bu C ++ programcıları için iyi bir tavsiye olsa da, C olarak etiketlenmiş soruya en ufak bir cevap vermez. C'de, önek veya postfix kullanmanız kesinlikle fark etmez.
Lundin

@Pacerier Soru yalnızca C ve C olarak etiketlenmiştir. Neden bununla ilgilenmediklerini düşünüyorsunuz? SO'nun nasıl çalıştığı göz önüne alındığında , Java, C #, COBOL veya başka bir konu dışı dil yerine sadece C ile ilgilendiklerini varsaymak akıllıca olmaz mıydı ?
Lundin

18

Kısa cevap:

Hız arasında i++ve ++ihızda hiçbir fark yoktur . İyi bir derleyici iki durumda farklı kod oluşturmamalıdır.

Uzun cevap:

Diğer cevapların bahsetmediği şey, ++ikarşısındaki farkın i++sadece bulduğu ifade içinde mantıklı olduğudur.

Durumunda for(i=0; i<n; i++), i++kendi ifadesinde yalnızdır: önce dizi nokta var i++ve ondan sonra bir tane var. Bu şekilde oluşturulan tek makine kodu "artış iile 1" ve programın geri kalanına ilişkin olarak sekanslanır ne kadar iyi tanımlanmıştır. Yani önek değiştirmek olsaydı ++, meselenin ufak, hala sadece makine kodu "artışı alacağı olmazdı itarafından 1".

Arasındaki farklar ++ive i++gibi ifadelerde sadece konularda array[i++] = x;karşı array[++i] = x;. Bazıları, bu tür işlemlerde postfix'in daha yavaş olacağını söyleyebilir ve daha isonra yeniden yüklenmesi gereken kayıtlar olduğunu söyleyebilir . Ancak, derleyici, C standardının dediği gibi "soyut makinenin davranışını bozmadığı" sürece talimatlarınızı istediği şekilde sipariş etmekte özgür olduğunu unutmayın.

Yani bunun array[i++] = x;makine koduna çevrildiğini varsayabilirsiniz :

  • iA kaydındaki mağaza değeri.
  • Dizinin adresini B kaydında saklayın.
  • A ve B ekleyin, sonuçları A'da saklayın.
  • A ile temsil edilen bu yeni adreste x değerini saklayın.
  • iA kaydındaki mağaza değeri // verimsiz çünkü burada ekstra talimat var, bunu zaten bir kez yaptık.
  • Artırma kaydı A.
  • A kaydını saklayın i.

derleyici kodu daha verimli üretebilir, örneğin:

  • iA kaydındaki mağaza değeri.
  • Dizinin adresini B kaydında saklayın.
  • A ve B ekleyin, sonuçları B'de saklayın.
  • Artırma kaydı A.
  • A kaydını saklayın i.
  • ... // kodun geri kalanı.

Bir C programcısı olarak postfix'in ++sonunda olduğunu düşünecek şekilde eğitilmiş olmanızdan dolayı , makine kodunun bu şekilde sipariş edilmesi gerekmez.

Bu nedenle ++C'deki önek ve postfix arasında bir fark yoktur . Şimdi C programcısı olarak çeşitlilik göstermeniz gereken şey, bazı durumlarda tutarsız bir şekilde önek ve diğer durumlarda da postfix kullanan insanlardır. Bu, C'nin nasıl çalıştığından veya dil hakkında yanlış bilgiye sahip olduklarından emin olmadıklarını gösterir. Bu her zaman kötü bir işarettir, programlarında batıl inançlara veya "dini dogmalara" dayanarak başka şüpheli kararlar aldıklarını ileri sürmektedir.

"Önek ++her zaman daha hızlıdır" aslında C programcıları arasında yaygın olan yanlış bir dogmadır.


3
Hiç kimse "Prefix ++ her zaman daha hızlıdır" demedi. Bu yanlış. Dedikleri şey "Postfix ++ asla daha hızlı değildir".
Pacerier

2
@Pacerier Belirli bir kişiden alıntı yapmıyorum, sadece geniş çaplı, yanlış bir inançtan söz ediyorum.
Lundin

@rbaleksandar C ++! = C.
Lundin

@rbaleksandar Soru ve cevap C ++ hakkında konuşuyor. Operatörün aşırı yüklenmesi ve kopya yapıcıları
Lundin

3
@rbaleksandar c ++ == c && ++ c! = c
sadljkfhalskdjfh

17

Scott Meyers'den bir yaprak almak, Daha Etkili c ++ Madde 6: Artış ve azaltma işlemlerinin önek ve son düzeltme formları arasında ayrım yapın .

Önek sürümü, nesneler açısından, özellikle yineleyiciler açısından postfix'e göre her zaman tercih edilir.

Bunun nedeni, operatörlerin çağrı düzenine bakarsanız.

// Prefix
Integer& Integer::operator++()
{
    *this += 1;
    return *this;
}

// Postfix
const Integer Integer::operator++(int)
{
    Integer oldValue = *this;
    ++(*this);
    return oldValue;
}

Bu örneğe bakıldığında, önek operatörünün postfix'ten her zaman nasıl daha verimli olacağını görmek kolaydır. Postfix kullanımında geçici bir nesneye ihtiyaç duyulduğundan.

Bu nedenle yineleyicileri kullanan örnekler gördüğünüzde her zaman önek sürümünü kullanırlar.

Ancak int için işaret ettiğiniz gibi, derleyici optimizasyonu nedeniyle etkili bir fark yoktur.


4
Bence sorusu C'ye yönelikti, ama C ++ için kesinlikle haklısın ve ayrıca C insanlar bunu C ++ için de kullanabildikleri için benimsemelidir. Çok sık C programcılarının postfix sözdizimini kullandığını görüyorum ;-)
Anders Rune Jensen

-1 Bu C ++ programcıları için iyi bir tavsiye olsa da, C olarak etiketlenmiş soruya en ufak bir cevap vermez. C'de, önek veya postfix kullanmanız kesinlikle fark etmez.
Lundin

1
@Lundin öneki ve postifx, Andreas'ın cevabına göre C'de önemlidir . Derleyicinin optimize edeceğini varsayamazsınız
JProgrammer

@JProgrammer Cevabınıza göre içtenlikle önemli değil :) Farklı kodlar verdiklerini fark ederseniz, bunun nedeni ya optimizasyonları etkinleştirememeniz ya da derleyicinin kötü olmasıdır. Her neyse, soru C ile ilgili olduğu için cevabınız konu dışı
Lundin

16

Mikro optimizasyon konusunda endişeleriniz varsa ek bir gözlem. Azalan döngüler, artan döngülerden (muhtemelen komut seti mimarisine, örneğin ARM'ye bağlı olarak) daha etkili olabilir:

for (i = 0; i < 100; i++)

Her döngüde her biri için bir talimatınız olacaktır:

  1. Ekleme 1için i.
  2. Olmadığını karşılaştırın ibir daha azdır 100.
  3. Koşullu dal i, a'dan küçükse 100.

Oysa azalan bir döngü:

for (i = 100; i != 0; i--)

Döngünün her biri için bir talimatı olacaktır:

  1. iCPU kayıt durumu bayrağını ayarlayarak azalma .
  2. CPU kayıt durumuna ( Z==0) bağlı bir koşullu dal .

Tabii ki bu sadece sıfıra inerken işe yarar!

ARM Sistem Geliştirici Kılavuzu'ndan hatırlanmıştır.


İyi bir. Ancak bu, daha az önbellek isabet yaratmaz mı?
AndreasT

Sıfır test dalının avantajını artırılmış adresle birleştiren kod optimizasyon kitaplarından eski bir garip hile var. İşte üst düzey dilde örnek (muhtemelen pek işe yaramaz, çünkü birçok derleyici daha az verimli ancak daha yaygın döngü koduyla değiştirilecek kadar akıllıdır ): int a [N]; (i = -N; i; ++ i) için bir [N + i] + = 123;
noop

@ noop muhtemelen hangi kod optimizasyon kitaplarına başvurduğunuzu açıklayabilir misiniz? İyi olanları bulmak için mücadele ettim.
mezamorfik

7
Bu cevap sorunun cevabı değildir.
monokrome

@mezamorphic x86 için kaynaklarım: Intel optimizasyon kılavuzları, Agner Fog, Paul Hsieh, Michael Abrash.
noop

11

Lütfen "hangisinin daha hızlı" sorusunun hangisinin kullanılacağına karar verme faktörü olmasına izin vermeyin. Muhtemelen hiç bu kadar çok umursamayacaksınız ve ayrıca programcı okuma süresi makine zamanından çok daha pahalı.

Kodu okuyan insan için en anlamlı olanı kullanın.


3
Gerçek verimlilik kazanımları ve genel niyet netliğine göre belirsiz okunabilirlik geliştirmelerini tercih etmenin yanlış olduğuna inanıyorum.
noop

4
"Programcı okuma süresi" terimim kabaca "niyet netliği" ile benzerdir. "Gerçek verimlilik kazançları" genellikle ölçülemez, sıfır olarak adlandırılacak kadar sıfıra yakındır. OP'nin durumunda, kod ++ i'nin bir darboğaz olduğunu bulmak için profillenmedikçe, hangisinin daha hızlı olduğu sorusu zaman kaybı ve programcı düşünce birimleri.
Andy Lester

2
++ i ve i ++ arasındaki okunabilirlik farkı sadece kişisel tercih meselesidir, ancak ++ i açıkça derleyici optimize edilirken önemsiz durumlar ve basit veri türleri için eşdeğer olmasına rağmen i ++ 'dan daha basit bir işlem gerektirir. Bu nedenle ++ i, artım sonrası belirli özellikler gerekli olmadığında benim için bir kazanan.
noop

Ne dediğimi söylüyorsun. Niyet göstermek ve okunabilirliği geliştirmek "verimlilik" konusunda endişelenmekten daha önemlidir.
Andy Lester

2
Hala katılıyorum. Okunabilirlik öncelikler listenizde daha yüksekse, programlama dili seçiminiz yanlış olabilir. C / C ++ birincil amacı verimli kod yazmaktır.
noop

11

Her şeyden önce: i++ve arasındaki fark ++iC cinsinden ayrılmazdır.


Detaylara.

1. Bilinen C ++ sorunu: ++idaha hızlı

C ++, ++idaha verimli iff iaşırı yüklenmiş bir artış operatörü ile bir nesne türüdür.

Neden?
İçinde ++i, nesne ilk olarak artırılır ve daha sonra başka herhangi bir fonksiyona bir sabit referans olarak geçirilebilir. İfadenin foo(i++)daha önce yapılması gereken çağrının foo()çağrılması, ancak eski değerin iletilmesi gerektiği için bu ifade mümkün değilse bu mümkün değildir foo(). Sonuç olarak, derleyici, iartan işleci orijinal üzerinde çalıştırmadan önce bir kopyasını almak zorunda kalır . Ek kurucu / yıkıcı çağrıları kötü kısımdır.

Yukarıda belirtildiği gibi, bu temel tipler için geçerli değildir.

2. Az bilinen gerçek: daha hızlı i++ olabilir

Hiçbir kurucu / yıkıcı çağrılmaya ihtiyaç duyulmuyorsa, bu her zaman C'deki durumdur ++ive i++eşit derecede hızlı olmalıdır, değil mi? Hayır. Neredeyse aynı derecede hızlıdırlar, ancak diğer cevaplayıcıların çoğunun yanlış yol aldıkları küçük farklılıklar olabilir.

Nasıl i++daha hızlı olabilir ?
Mesele veri bağımlılıklarıdır. Değerin bellekten yüklenmesi gerekiyorsa, onunla sonraki iki işlemin yapılması, artırılması ve kullanılması gerekir. İle ++i, değerin kullanılabilmesi için önce artım yapılmalıdır . İle i++kullanım, artışa bağlı değildir ve CPU, kullanım işlemini artış işlemine paralel olarak gerçekleştirebilir. Fark en fazla bir CPU döngüsüdür, bu yüzden gerçekten pazarlık edilebilir, ancak orada. Ve o zamanlar birçoğunun beklediği başka bir yol.


2. noktanız hakkında: ++iveya i++ifadesi başka bir ifadede kullanılıyorsa, bunlar arasında geçiş yapmak ifadenin anlambilimini değiştirir, dolayısıyla olası herhangi bir performans kazancı / kaybı söz konusu değildir. Bağımsızlarsa, yani işlemin sonucu hemen kullanılmazsa, iyi bir derleyici onu aynı şeye derler, örneğin bir INCmontaj talimatı.
Shahbaz

1
@Shahbaz Bu tamamen doğru, ama önemli değil. 1) Anlambilim farklı olsa da, her ikisi de i++ve ++idöngü sabitlerini bir ayarlayarak hemen hemen her durumda birbirinin yerine kullanılabilir, böylece programcı için yaptıkları işte eşdeğerdirler. 2) Her ikisi de aynı talimatı derlemesine rağmen, işlemcileri CPU için farklıdır. Böyle bir durumda i++, CPU artışı aynı değeri kullanan başka bir talimata paralel olarak hesaplayabilir (CPU'lar bunu gerçekten yapar!), ++iCPU ile birlikte diğer talimatları zamanlamadan sonra programlamak zorundadır .
cmaster

4
@Shahbaz Örnek olarak: if(++foo == 7) bar();ve if(foo++ == 6) bar();işlevsel olarak eşdeğerdir. Bununla birlikte, ikincisi bir döngü daha hızlı olabilir, çünkü karşılaştırma ve artış CPU tarafından paralel olarak hesaplanabilir. Bu tek döngü çok önemli değil, ama fark var.
cmaster - reinstate monica

1
İyi bir nokta. Sabitler genellikle kullanılan yerlerde çok fazla ( <örneğin vs gibi <=) görünür ++, bu nedenle düşünce arasındaki dönüşüm genellikle kolayca mümkündür.
Shahbaz

1
Ben nokta 2 seviyorum, ama bu sadece değer kullanılırsa geçerlidir, değil mi? Soru, "ortaya çıkan değer kullanılmazsa?" Diyor, bu yüzden kafa karıştırıcı olabilir.
jinawee

7

@Mark Derleyicinin değişkenin (yığın tabanlı) geçici kopyasını optimize etmesine izin verilse de ve gcc (son sürümlerde) bunu yapıyor olsa da, tüm derleyicilerin her zaman bunu yapacağı anlamına gelmez .

Sadece mevcut projemizde kullandığımız derleyicilerle test ettim ve 4'ten 3'ü optimize etmiyor.

Özellikle derhal daha hızlı, ancak daha yavaş olan kodun okunması kolay değilse, derleyicinin doğru olduğunu varsaymayın.

Kodunuzdaki operatörlerden birinin gerçekten aptalca bir uygulaması yoksa:

Alwas ++ i i ++ 'ı tercih eder.


Sadece merak ediyorum ... neden bir projede 4 farklı C derleyicisini kullanıyorsunuz? Yoksa bu konuda bir takımda mı yoksa bir şirkette mi?
Lawrence Dol

3
Konsollar için oyun oluştururken her platform kendi derleyicisini / araç zincirini getiriyor. Mükemmel bir dünyada yarar bir gcc / çınlama / LLVM tüm hedefler için, ama bu dünyada biz vs Microsoft, Intel, Metroworks, Sony, katlanmak zorunda
Andreas

5

C dilinde, derleyici genellikle sonuç kullanılmazsa bunları aynı olacak şekilde optimize edebilir.

Ancak, C ++ 'da kendi ++ işleçlerini sağlayan diğer türler kullanılıyorsa, önek sürümünün postfix sürümünden daha hızlı olması muhtemeldir. Bu nedenle, postfix semantiğine ihtiyacınız yoksa, önek operatörünü kullanmak daha iyidir.


4

Postfix önek artış daha yavaş olduğu bir durum düşünebilirsiniz:

Kayıtlı bir işlemcinin Aakümülatör olarak kullanıldığını ve birçok talimatta kullanılan tek kayıt olduğunu düşünün (bazı küçük mikrodenetleyiciler aslında böyle).

Şimdi aşağıdaki programı ve bunların varsayımsal bir düzene dönüştürülmesini hayal edin:

Önek artışı:

a = ++b + c;

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

Postfix artışı:

a = b++ + c;

; load b
LD    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

Değerinin nasıl byeniden yüklenmeye zorlandığına dikkat edin. Önek artışı ile, derleyici sadece değeri arttırabilir ve kullanmaya devam edebilir, muhtemelen istenen değer artımdan sonra kayıtta olduğundan, yeniden yüklemekten kaçının. Ancak, postfix artışı ile, derleyicinin biri eski diğeri artan değeri olmak üzere iki değerle uğraşması gerekir, bu da yukarıda gösterdiğim gibi bir bellek erişimine neden olur.

Tabii ki, artışın değeri tek bir i++;ifade gibi kullanılmazsa, derleyici postfix veya önek kullanımından bağımsız olarak bir arttırma talimatı oluşturabilir (ve yapar).


Bir yan not olarak, içinde bir ifadenin herhangi bir ek çaba olmadan bir ifadeye b++dönüştürülemeyeceğinden bahsetmek istiyorum ++b(örneğin a ekleyerek - 1). Bu yüzden ikisini bir ifadenin parçasıysa karşılaştırmak gerçekten geçerli değildir. Genellikle, kullanamayacağınız b++bir ifadenin içinde kullandığınız yerde ++b, ++bpotansiyel olarak daha verimli olsa bile , bu sadece yanlış olur. Tabii ki, ifade bunun için yalvarıyorsa (örneğin a = b++ + 1;, değiştirilebilir a = ++b;).


4

Buradaki cevapların çoğunu ve yorumların çoğunu okudum ve nerede daha etkili (ve şaşırtıcı bir şekilde daha etkili ) olduğunu düşünebildiğim tek bir örneğe başvurmadım . Bu DEC PDP-11 için C derleyicileri için!i++++i--i i--

PDP-11, bir kaydın azaltılması ve arttırma sonrası montaj talimatlarına sahipti, ancak bunun tersi değildi. Talimatlar, herhangi bir "genel amaçlı" kaydın bir yığın işaretçisi olarak kullanılmasına izin verdi. Yani böyle bir şey kullandıysanız *(i++), tek bir montaj talimatında derlenebilir, ancak *(++i)yapamazsınız.

(Veya demeliyim Bu tabii ki bir çok ezoterik örnektir, ama sonradan arttırma daha etkilidir istisna sağlamaz oldu bu gün PDP-11 C kodu için fazla talep olmadığından,).


2
Çok ezoterik, ama çok ilginç!
Mark Harrison

@daShier. +1, katılmıyorum da, bu o kadar ezoterik değil ya da en azından olmamalı. C, PDP-11'in hedef işlemci olduğu 70'li yılların başlarında Unix ile AT&T Bell Labs'da birlikte geliştirildi. Bu dönem sonrası artıştaki Unix kaynak kodunda, "i ++", kısmen geliştiricilerin değerin ne zaman atandığını, "j = i ++" veya bir dizin olarak "a [i ++] = n" kullanıldığını bildikleri için daha yaygındır. kod biraz daha hızlı (ve daha küçük) olacaktır. Ön gerekmedikçe artım sonrası kullanma alışkanlığı kazanmış gibi görünüyor. Diğerleri kodlarını okuyarak öğrendiler ve bu alışkanlığı da aldılar.
jimhark

68000 aynı özelliğe sahiptir, arttırma sonrası ve azaltma donanımda (adresleme modları olarak) desteklenir, ancak tersi şekilde desteklenmez. Motorola ekibi, DEC PDP-11'den ilham aldı.
jimhark

2
@jimhark, evet, 68000 aktarılacak ve hala kullananlar PDP-11 programcılar biriyim --ive i++.
daShier

2

Her zaman ön artışı tercih ederim, ancak ...

Ben işleç ++ işlev çağrıldığında bile, işlev satır içine alırsa derleyici geçici optimize mümkün olacağını işaret etmek istedim. ++ işleci genellikle kısa olduğundan ve genellikle üstbilgide uygulandığından, satır içine alma olasılığı yüksektir.

Dolayısıyla, pratik amaçlar için, iki formun performansı arasında büyük bir fark yoktur. Bununla birlikte, her zaman ön artışı tercih ederim, çünkü anlamaya çalıştığım optimize ediciye güvenmek yerine söylemeye çalıştığım şeyi doğrudan ifade etmek daha iyi görünüyor.

Ayrıca, optimize ediciye daha az şey yapması derleyicinin daha hızlı çalıştığı anlamına gelir.


Sizin gönderme ++ C - özgü soru Her durumda C hakkında ise, cevabın yanlıştır: özel artırma sonrası operatörleri için derleyici genellikle edecek değil verimli kod olarak üretmek mümkün.
Konrad Rudolph

"İşlev satır içine girerse" der ve bu da akıl yürütmesini doğru kılar.
Blaisorblade

C operatörün aşırı yüklenmesini sağlamadığından, öncesi ve sonrası sorusu büyük ölçüde ilgisizdir. Derleyici kullanılmayan sıcaklığı geçici olarak kullanılmayan ilkel olarak hesaplanan herhangi bir değere uygulanan mantığı kullanarak optimize edebilir. Bir örnek için seçilen cevaba bakınız.

0

C'm biraz paslı, bu yüzden şimdiden özür dilerim. Hızla sonuçları anlayabiliyorum. Ancak, her iki dosyanın da aynı MD5 karmasına nasıl geldiği konusunda kafam karıştı. Belki bir for döngüsü aynı çalışır, ancak aşağıdaki 2 kod satırı farklı montaj üretmez mi?

myArray[i++] = "hello";

vs

myArray[++i] = "hello";

Birincisi, değeri diziye yazar, sonra i değerini artırır. İkinci i artışları daha sonra diziye yazar. Ben montaj uzmanı değilim, ama sadece aynı yürütülebilir kod bu 2 farklı kod satırı tarafından oluşturulacak görmüyorum.

Sadece iki sentim.


1
@Jason Z Derleyici optimizasyonu, montaj üretilmeden önce gerçekleşir, i değişkeninin aynı satırda başka hiçbir yerde kullanılmadığını görür, bu nedenle değerini tutmak israf olur, muhtemelen etkili bir şekilde i ++ 'a çevirir. Ama bu sadece bir tahmin. Öğretim üyelerimden birinin daha hızlı olduğunu söylemeye çalışmasını bekleyemiyorum ve bir teoriyi pratik kanıtlarla düzelten adam olmaya başladım. Neredeyse düşmanlığı hissedebiliyorum ^ _ ^
Tarks

3
"C'm biraz paslı, bu yüzden şimdiden özür dilerim." C'nizde yanlış bir şey yok, ancak orijinal soruyu tam olarak okumadınız: " Sonuçta elde edilen değer kullanılmazsa i ++ ve ++ i arasında bir performans farkı var mı ? " Senin Örneğin i ++ / ++ i, 'sonuç' olarak edilir derleyici bunu sever ne yapabilirim böylece kullanılabilir, ancak döngü deyimsel içinde, ön / postincrement operatörün 'sonuç' kullanılmaz.
Roddy

2
örneğinizde kod farklı olacaktır, çünkü değeri kullanıyorsunuz. aynı oldukları örnek yalnızca artış için ++ kullanmaktı ve her ikisinin de döndürdüğü değeri kullanmıyordu.
John Gardner

1
Düzeltme: "derleyici i ++ dönüş değerinin kullanılmadığını görürdü, bu yüzden ++ i çevirir". Yazdığınız şey yanlış, çünkü i'yi aynı satırda (ifade) i ++, i ++ ile birlikte tutamazsınız, bu sonuç tanımsızdır.
Blaisorblade

1
Değişen foo[i++]için foo[++i]açıkçası programı semantiğini değiştirecek başka bir şey değiştirmeden, ancak bazı işlemciler üzerinde bir döngü kaldırma optimizasyon mantığı olmadan bir derleyici kullanırken, artan pve qörneğin gerçekleştirdiği bir döngü çalışan daha sonra bir kez ve *(p++)=*(q++);daha hızlı olan gerçekleştirdiği bir döngü kullanmaktan daha olacaktır *(++pp)=*(++q);. Bazı işlemcilerdeki çok sıkı döngüler için hız farkı önemli olabilir (% 10'dan fazla), ancak muhtemelen C'de artışın artışın önünden daha hızlı olduğu tek durumdur.
supercat
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.