Neden postfix artışımız var?


55

Feragatname : Önek ve sonek artışının anlamını çok iyi biliyorum. Lütfen bana nasıl çalıştıklarını açıklama.

Yığın taşması ile ilgili soruları okurken yardım edemem ama programcıların postfix artrım operatörü tarafından tekrar tekrar karıştığını fark ettim. Bundan şu soru ortaya çıkar: Postfix artışının kod kalitesi açısından gerçek bir fayda sağladığı herhangi bir kullanım durumu var mı?

Sorumu bir örnekle açıklığa kavuşturmama izin verin. İşte süper özlü bir uygulama strcpy:

while (*dst++ = *src++);

Ancak bu, kitabımdaki en çok kendi kendini belgeleyen kod değil (ve aklı başında derleyiciler için iki sinir bozucu uyarı da veriyor). Öyleyse aşağıdaki alternatifte yanlış olan ne?

while (*dst = *src)
{
    ++src;
    ++dst;
}

Böylece durumdaki kafa karıştırıcı atamadan kurtulabilir ve tamamen uyarı gerektirmeyen bir kod alabiliriz:

while (*src != '\0')
{
    *dst = *src;
    ++src;
    ++dst;
}
*dst = '\0';

(Evet, biliyorum srcve dstbu alternatif çözümlerde farklı son değerlere sahip olacağım, ancak strcpydöngüden hemen sonra geri döndüğü için, bu durumda önemli değil.)

Postfix artışının amacı, kodu olabildiğince kısa ve öz yapmaktır. Bunun nasıl bir çaba sarf etmemiz gerektiğini göremiyorum. Bu başlangıçta performansla ilgiliyse, bugün hala geçerli mi?


7
Postfix varyantı en yaygın kullanılanıdır, bu nedenle aleyhinize bir dava açacaksanız, oldukça güçlü bir dava olsa iyi olur. Ve ilk örneğiniz biraz sert bir adam, zira çok az insanın strcpymetodu bu şekilde kodlayacağından şüpheleniyorum (daha önce bahsettiğiniz sebeplerden dolayı).
Robert Harvey,

4
Neden ya hiç?
James McNell,

31
Programcıları şaşırtma potansiyeli olan dillerden her şeyi çıkarırsak, çok fazla özelliğe sahip olamayız. Bir şeyin sizin için yararlı olmadığı ya da çok nadiren yararlı olduğu gerçeği , kırılması gerektiği anlamına gelmez. Artık alakalı değilse, kullanmayın; son.
Cody Gray,

4
Evet ama o zaman asla yapamazsınint c = 0; c++;
Biff MaGriff

4
@Cody: Çünkü bazı şeyler kafa karıştırıcı ve kullanışlıdır. Artış sonrası kendisinin kafası karışmaz, faydası hakkında kafası karışır . İşe yaramaz, kafa karıştırıcı ya da olmayan şeylere sahip olmamalıyız.
GManNickG

Yanıtlar:


23

Bir zamanlar bazı performans etkileri olsa da, asıl nedenin niyetinizi temiz bir şekilde ifade etmektir. Asıl soru, bir şeyin while (*d++=*s++);niyeti açıkça ifade edip etmediğidir. IMO, bunu yapar ve ben size sunduğunuz alternatifleri daha az net bir şekilde bulurum - ama bu, onlarca yıl işlerin nasıl yapıldığına alışmış olmanın bir sonucu olabilir. K & R'den C öğrenmiş olmak (çünkü o zamanlar C ile ilgili neredeyse hiç kitap yoktu) büyük olasılıkla da yardımcı oluyor.

Bir dereceye kadar, tersliklerin eski kodlarda çok daha büyük bir değere sahip olduğu doğrudur. Şahsen, bunun büyük ölçüde iyi bir şey olduğunu düşünüyorum - birkaç kod satırının anlaşılması genellikle oldukça önemsizdir; zor olan büyük kod parçalarını anlamak. Testler ve çalışmalar, art arda tüm kodların ekrana bir seferde sığdırılmasının kodu anlamada ana faktör olduğunu göstermiştir. Ekranlar genişledikçe, bu gerçek gibi gözüküyor, bu nedenle kodu (makul ölçüde) kısa tutmanız değerli.

Elbette denize girmek mümkün ama bunun olduğunu sanmıyorum. Özellikle, tek bir kod satırını anlamak son derece zor ya da zaman alıcı hale geldiğinde denize düşeceğini düşünüyorum - özellikle de daha az kod satırını anlamak, daha fazla satır anlamaktan daha fazla çaba gerektirir. Lisp ve APL'de sık sık görülür, fakat burada (en azından bana) öyle görünmüyor.

Derleyici uyarıları hakkında daha az endişe duyuyorum - birçok derleyicinin oldukça düzenli bir şekilde tamamen saçma uyarılar yayması benim deneyimim. İnsanların kodlarını (ve üretebilecekleri herhangi bir uyarıyı) anlaması gerektiğini düşündüğüm halde, bazı derleyicilerde bir uyarıyı tetikleyen iyi kod mutlaka yanlış değildir. Kuşkusuz, yeni başlayanlar her zaman güvenli bir şekilde ne görmezden gelebileceklerini bilmezler, ama biz sonsuza dek yeni başlayanlar olarak kalmayız ve bizim gibi kodlamaya gerek yoktur.


12
Kısa versiyonun bazılarımıza okumasının daha kolay olduğunu vurgulamak için +1 . :-)

1
Eğer derleyici uyarısı bazı beğenmezseniz (ve olmadan yapabileceğini birkaç daha var - cidden geliyordu türüne if(x = y), yemin ederim!) Yanlışlıkla kaçırmamak Eğer derleyici 'uyarıları seçeneklerini ayarlamak gerekir Eğer uyarılar do gibi.

4
@ Moses Brooks: Bu konuda çok daha az heyecanlıyım. Derleyicinin eksikliklerini gidermek için kodumu kirletmekten hoşlanmıyorum.
Jerry Coffin

1
@Jerry, @Chris: Bu açıklama, uyarının genellikle iyi bir şey olduğunu düşündüğünüz durum için düşünülmüştür , ancak bunun olağandışı bir şey yapan belirli bir satıra uygulanmasını istemezsiniz. Uyarıyı asla istemez ve bir eksiklik olduğunu düşünürseniz, kullanın -Wno-X, ancak yalnızca bir istisna yapmak ve uyarının başka bir yere uygulanmasını istiyorsanız, bu, Chris'in bahsettiği gibi ateşli çember atlama kullanmaktan çok daha anlaşılır bir durumdur. .

1
@Brooks: çift parantez ve (void)xkullanılmayan uyarıları susturmak, aksi takdirde yararlı uyarıları susturmak için oldukça iyi bilinen deyimlerdir. Ek açıklama gibi biraz görünüyor pragmasdeğil taşınabilir, en iyi: /
Matthieu M.

32

Bu, donanımsal bir şeydi.


Dikkatini çekmek ilginç. Sonek artışı muhtemelen bir takım mükemmel sebeplerden ötürü orada olabilir, fakat C'deki birçok şey gibi, popülerliği dilin kökenine kadar izlenebilir.

Her ne kadar C, çeşitli erken ve düşük güçte makineler üzerinde geliştirilse de, C ve Unix ilk önce PDP-11'in bellekle yönetilen modelleri ile göreceli olarak büyük zamanlarını etkiledi. Bunlar günlerinde göreceli olarak önemli bilgisayarlardı ve Unix, -11 için mevcut olan diğer 7 ufak işletim sistemlerinden çok daha iyi - katlanarak daha iyi - idi.

Ve öyle olur, PDP-11’de,

*--p

ve

*p++

... donanım olarak adresleme modları olarak uygulandı . (Ayrıca *p, ancak başka bir kombinasyon yoktur.) Bu eski makinelerde, tümü 0,001 GHz'den daha az , bir döngüyü ya da ikisini bir döngüde kaydetmek neredeyse bir saniye beklemek ya da bir dakika beklemek ya da çıkmak için yapılmış olmalıdır. -Lunch farkı. Bu tam olarak özel olarak postincrement ile konuşmuyor, ancak pointer postincrement ile bir döngü o zaman indekslemekten çok daha iyi olabilirdi.

Sonuç olarak, tasarım desenleri çünkü C zihinsel makro haline gelen C deyimleri.

Bundan hemen sonra değişkenleri bildirmek gibi bir şey {... bir C89'un mevcut olmasından bu yana bir gereklilikti, ama şimdi bir kod kalıbı.

Güncelleme: Açıkçası, ana neden *p++, dilde olması, tam olarak ne yapmak istediğinin tam olarak olmasıdır. Kod şablonunun popülaritesi , PDP-11'in gelmesinden biraz önce tasarlanan bir dilin halihazırda var olan şablonuyla birlikte gelen ve eşleşen popüler donanım ile pekiştirildi .

Bu günlerde hangi modeli kullandığınız ya da indeksleme kullanıyorsanız farketmez ve genellikle yine de daha yüksek bir seviyede programlıyoruz, ancak bu 0.001GHz makinelerde çok önemli olması gerekiyordu ve sizin *--xveya dışında bir şey kullanmak *x++PDP-11'i "alamadım" ve insanların size gelip "bunu biliyor muydunuz ..." diyeceğini söyleyebilirdiniz :-) :-) :-)


25
Vikipedi diyor: "A (yanlış) halk efsanesi PDP-11 komut kümesi mimarisi C programlama dilinin deyimsel kullanımını etkilemiş olmasıdır PDP-11'in arttırma ve eksiltme adresleme modları karşılık gelmektedir. −−iVe i++C If deki yapılardaki ive jHer ikisi de kayıt değişkenleridi, *(−−i) = *(j++)tek bir makine komutuna derlenebilecek bir ifade . [...] Dennis Ritchie açıkça bu halk efsanesine
aykırıydı

3
Huh (FredOverflow'un yorumunda verilen bağlantıdan): "İnsanlar genellikle, C ve Unix'in ilk popüler olduğu DEC PDP-11 tarafından sağlanan otomatik artırma ve otomatik azaltma adres modlarını kullanmak için yaratıldıklarını tahmin ediyorlar. Bu, tarihsel olarak imkansız, çünkü B geliştirildiğinde PDP-11 yoktu .. PDP-7'de, bir 'otomatik artan' bellek hücresi vardı, dolaylı bir bellek referansının hücreyi arttırdığı özelliği ile. Bu operatörlere Thompson'a öneride bulundu; hem ön hem de posta ekini yapma genellemesi onun oldu. ”

3
DMR sadece PDP-11'in C'ye eklenmesinin nedeni olmadığını söyledi. Söylediğim şey, PDP-11’de avantaj sağlamak için kullanıldığı ve bu nedenle bu nedenle popüler bir tasarım deseni olduğu idi. Vikipedi bununla çelişiyorsa, o zaman onlar sadece yanlış, ama ben o şekilde okumam. Bu W sayfasında kötü bir şekilde ifade edilir.
DigitalRoss

3
@FredOverflow. Bence "halk efsanesi" nin ne olduğunu tam olarak yanlış anladınız. Efsaneye göre, C, bu 11 operasyondan yararlanmak için tasarlandı, var olmadıklarından ve kod şablonunun popüler olmadığından değil, çünkü herkes 11 kuyucuğa eşlendiğini biliyordu. Net olmadığı durumda: PDP-11 gerçekten bu iki modu donanımda hemen hemen her komut için bir adresleme modu olarak uygular ve bu gerçekten C'nin çalıştırdığı ilk önemli makineydi.
DigitalRoss

2
"Bu 0.001GHz makinelerde çok önemli olmalıydı". Bana geldiği için söylemekten nefret ediyorum, ancak CPU'larımın talimatların boyutuna ve kaç döngü aldıklarına bakmak için Motorola ve Intel kılavuzları vardı. Bir yazdırma biriktiricisine bir özellik daha ekleyebilmek için eklenen en küçük kodları bulmak ve birkaç döngüden tasarruf etmek, seri portun yeni oluşturulan MIDI gibi bazı protokollere yetişebileceği anlamına geliyordu. C, özellikle derleyiciler geliştikçe nitelemenin bir kısmını rahatlattı, ancak yine de kod yazmanın en etkili yolunun ne olduğunu bilmek önemliydi.
Teneke Adam

14

Önek ve sonek --ve ++operatörler B dilinde (C selefi) Ken Thompson tarafından tanıtıldı - ve hayır, o sırada bulunmayan PDP-11'den ilham almadılar.

Dennis Ritchie'nin "C Dilinin Gelişimi" nden alıntı :

Thompson ++ve icadı bir adım daha ileri gitti--artan veya azalan operatörler; önek veya sonek konumları, değişimin işlenenin değerini not etmeden önce mi sonra mı olacağını belirler. B'nin ilk versiyonlarında değildiler ama yol boyunca belirdiler. İnsanlar genellikle C ve Unix'in ilk popüler olduğu DEC PDP-11 tarafından sağlanan otomatik artırma ve otomatik azaltma adres modlarını kullanmak için yaratıldıklarını tahmin ediyorlar. Bu tarihsel olarak imkansız çünkü B geliştirildiğinde PDP-11 yoktu. Bununla birlikte, PDP-7, dolaylı bir hafıza referansının hücreyi arttırdığı özelliğiyle, birkaç 'otomatik artan' hafıza hücresine sahipti. Bu özellik muhtemelen bu tür operatörleri Thompson'a önermişti; Onları hem ön hem de son ek yapmak için yapılan genelleme kendisine aitti. Aslında,++xolandan daha küçüktü x=x+1.


8
Hayır, Ken Thompson ile ilgili değilim.
Keith Thompson

Bu çok ilginç referans için teşekkürler! Bu, teknik optimizasyon yerine kompaktlık hedefini öneren orijinal K&R'den teklifimi doğruladı. Ancak bu operatörlerin zaten B'de bulunduğunu bilmiyordum
Christophe

@BenPen Bildiğim kadarıyla , her iki soru da kendi sitelerine uygun olduğu sürece, farklı bir SE sitesinde yinelenen bir kişi varsa, soruları kapatma politikası yoktur .
Ordous

İlginç ... Programcı biri kesinlikle bir soruya yakın değil.
BenPen

@BenPen: Yığın Taşması sorusuna kabul edilen cevap zaten yaptığım aynı kaynağı gösteriyor (bunun kadar olmasa da).
Keith Thompson

6

Eğer gibi ifadeler yazmak zorunda kalmamak için varolma postincrement operatör için bariz nedeni (++x,x-1)veya (x+=1,x-1)her yerde ya faydasızca dışarı birden tablolara içine kolay anlaşılır yan etkileri olan önemsiz ifadeleri ayırın. İşte bazı örnekler:

while (*s) x+=*s++-'0';

if (x) *s++='.';

Bir dize ileri yönde okurken veya yazarken, postincrement ve preincrement değil, hemen hemen her zaman doğal bir işlemdir. Önceden kullanım için gerçek dünya kullanımlarıyla neredeyse hiç karşılaşmamıştım ve ön değerlendirme için bulduğum tek ana kullanım, sayıları dizgelere dönüştürmek (insan yazma sistemleri sayıları geriye doğru yazdığı için).

Düzenleme: Aslında o kadar çirkin olmaz; (++x,x-1)senin yerine elbette kullanabilirsin ++x-1ya da (x+=1)-1. Hala x++daha okunaklı.


İki sıra noktası arasındaki bir değişkeni değiştirdiğiniz ve okuduğunuz için bu ifadelere dikkat etmeniz gerekir. Bu ifadelerin değerlendirilme sırası garanti edilmez.

@Snowman: Hangisi? Cevabımda böyle bir sorun görmüyorum.
R.

Gibi bir şey varsa (++x,x-1)(işlev çağrısı, belki?)

@Snowman: Bu bir işlev çağrısı değil. Bir öncelik noktası olan C virgül operatörü, önceliği kontrol etmek için parantez içine alınır. Sonuç, x++çoğu durumda olduğu gibi aynıdır (bir istisna: xsıralamanın altında olan imzasız bir türdür intve başlangıç xdeğeri, bu türün maksimum değeridir).
R.

Ah, zor virgül operatörü ... virgül virgül olmadığında. Virgül operatörünün parantezi ve nadirliği beni attı. Boşver!

4

PDP-11, talimat setinde artırma ve azaltma öncesi işlemleri teklif etti. Şimdi bunlar talimat değildi. Bunlar, artırılmadan önce veya azaltıldıktan sonra bir kaydın değerini istediğinizi belirtmenizi sağlayan talimat değiştiricilerdi.

Makine dilinde bir kelime kopyalama adımı:

movw (r1)++,(r2)++

bir kelimeyi bir konumdan diğerine taşıyan, kayıtların işaret ettiği ve kayıtların tekrar yapmaya hazır olacağı.

C'nin üzerinde ve PDP-11 için yapıldığı için, birçok yararlı kavram C'ye girerken bulundu. C, assembler dili için yararlı bir alternatif olması amaçlandı. Simetri için ön arttırma ve azaltma sonrası eklendi.


Bu harika değiştiriciler ... PDP-11 montajını öğrenmek istememi sağlıyor. BTW, "simetri için" konulu bir referansınız var mı? Mantıklı, ama bu tarih, bazen mantıklı olmak anahtar değildi. LOL
BenPen 23:16

2
Adresleme modları olarak da bilinir . PDP-11, istif işlemleri için güzel bir şekilde bir araya getirilmiş olan artırma ve azaltma sonrası sağlar.
Erik Eidt

1
PDP-8, bir artım sonrası hafıza aktarımı sağladı, ancak karşılık gelen ön azaltma işlemi gerçekleştirmedi. Manyetik çekirdekli bellekle, bir bellek kelimesini okumak onu (!) Siler, böylece işlemci kelimeyi sadece okumak için geri yazma işlevini kullanır. Geri yazma işleminden önce bir artış yapılması doğal olarak gerçekleşmiştir ve daha verimli bir blok hareketi mümkün olmuştur.
Erik Eidt

3
Üzgünüz, PDP-11 bu operatörlere ilham vermedi. Ken Thompson onları icat ettiğinde henüz yoktu. Cevabımı gör .
Keith Thompson

3

Bunun gerçekten gerekli olduğundan şüpheliyim. Bildiğim kadarıyla, çoğu platformda, önceden yaptığınız gibi, döngüde kullandığınızdan daha fazla bir şey derlemiyor. Sadece, yapıldığı sırada kodun açıklığı, kodun açıklığından daha önemliydi.

Bu, kodun açıklığının önemli olmadığını (veya önemli olmadığını) değil, ancak her tuşa basmak zorunda kaldığı düşük bir baud modemi yazarken (baud'da ölçtüğünüz herhangi bir şey yavaş) anabilgisayar ve daha sonra parite kontrolü olarak kullanılan tek bir bit ile bir seferde bir bayt geri yankılandı, fazla yazmak istemedim.

Bu bir nevi and ve | == den daha düşük önceliğe sahip operatör

En iyi niyetlerle tasarlandı (kısa devre yapan && ve || sürümü), ancak şimdi programcıları her gün karıştırıyor ve muhtemelen hiç değişmeyecek.

Her neyse, bu sadece cevabınıza göre, cevabınıza iyi bir cevap olmadığını düşünüyorum, ama muhtemelen benden daha fazla guru kodlayıcı tarafından yanlış olarak ispatlanacağım.

--DÜZENLE--

Ben belirtmeliyiz ben hem inanılmaz faydalı bulmayanlar, ben sadece değişmeyeceğini işaret ediyorum olmadığını böyle kimse ya da değil.


Bu uzaktan bile doğru değil. Hiçbir noktada "kodun tersi" açıklıktan daha önemli değildi .
Cody Gray

Ben bunun çok daha fazla odaklanılacağını savunuyorum. Yine de oldukça haklısın, kesinlikle çoğu insan için kodun açıklığından ... daha önemli olmamıştı .

6
Eh, "terse" tanımı "düzgün zarif: cilalı" veya "çok az kelime kullanarak: fazlalıktan yoksun", her ikisi de kod yazarken genellikle iyi bir şeydir. "Terse" birçok insanın düşündüğü gibi "gizlenmemesi, okunması zor ve gizlenmemiş" anlamına gelmez.
James McNell,

@James: Doğru derken, çoğu insanın programlama bağlamında kullanırken "vecize" in ikinci tanımı anlamına geldiğini düşünüyorum : "çok az kelime kullanmak; fazlalıktan yoksun olmak". Bu tanım altında, belirli bir kod parçasının kısalık ve ifade edilebilirliği arasında bir denge olduğu durumları hayal etmek kesinlikle daha kolaydır. Açıkçası, kod yazarken yapılacak doğru şey konuşmadakiyle aynı şeydir: işleri olması gerektiği kadar kısa yapın, ancak daha kısa yapın. Expressivity üzerinde terseness değer vermek olabilir Karartılmış görünümlü koda sebep, ama kesinlikle olmamalı.
Cody Gray

1
40 yıl geriye sarın ve yalnızca 1000 karakter tutabilecek tambur üzerine programınıza uymanız gerektiğini düşünün ya da bir derleyici yalnızca 4 bin bayt koçla çalışabileceğini düşünün. Berraklığa karşı netliğin bir sorun olmadığı zamanlar vardı. Özlü olmak zorundaydın, bu gezegende özlü olmayan programınızı saklayabilecek, çalıştırabilecek ya da derleyebilecek bir bilgisayar yoktu.
nos

3

İşaretçilerle ilgilenirken postfix operatörünü seviyorum (bunları değiştirmeme veya değiştirmeme)

p++

"bir sonraki noktaya geç" ifadesiyle eşdeğerden daha doğal olarak okur

p += 1

bu kesinlikle yeni başlayanları ilk gördüğünde, sizeof (* p)! = 1.

Karışıklık sorununu doğru bir şekilde belirttiğinizden emin misiniz? Yeni başlayanların kafasını karıştıran şey, postfix ++ operatörünün dereference * operatöründen daha yüksek önceliğe sahip olmasıdır.

*p++

ayrıştırır

*(p++)

ve yok

(*p)++

bazıları beklediğiniz gibi?

(Bunun kötü olduğunu mu düşünüyorsun? Bkz . C Bildirimlerini Okuma .)


2

İyi programlamanın ince unsurları arasında yerelleşme ve minimalizm vardır :

  • değişkenleri minimum kullanım alanına koymak
  • Yazma erişimi gerekli olmadığında const kullanma
  • vb.

Aynı ruhla, x++bugünkü değerlerine referans yerini belirleyebilen bir yolu olarak görülebilir x, en azından şimdilik - - süre hemen ettik belirten olsun bu değerle bitmiş ve (sonraki taşımak için geçerli istiyorum xbir intveya bir işaretçi veya yineleyici). Küçük bir hayal gücü ile, xartık eski gerek duyulan değerin / pozisyonun artık gerekmedikten hemen sonra "kapsam dışı kalmasına" izin vermek ve yeni değere geçmekle karşılaştırılabilir. Bu geçişin mümkün olduğu kesin nokta postfix ile vurgulanır++ . Bunun muhtemelen "eski" nin son kullanımı xolduğu iddiası, algoritmaya, programlayıcıya etrafındaki kodda tarama yaparken yardımcı olmalarına yardımcı olabilir. Elbette, postfix++ programcıya, yeni değerin ne zaman gerekli olduğuna bağlı olarak iyi olabilen veya iyi olmayabilen yeni değerin kullanımına bakabilir, bu yüzden, neyin daha fazla olduğunu belirlemek için programlamanın "sanatı" veya "sanatı" nın bir yönüdür. şartlarda yardımcı.

Birçok yeni başlayan bir özellik tarafından karıştırılsa da, bunu uzun vadeli faydalara karşı dengelemeye değer: yeni başlayanlar uzun süre yeni başlayanlar için kalmaz.


2

Vay, pek de önemli olmayan pek çok cevap (eğer çok cesur olabilirsem), ve eğer bariz olduğuna işaret ediyorsam beni affet - özellikle de anlamını göstermemek için yorumunun ışığında (Stroustrup'un bakış açısından, sanırım) henüz gönderilmemiş gibi görünüyor! :)

Postfix x++, ifadede 'yukarı' geçen bir geçici üretir, değişken xdaha sonra artırılır.

Önek ++xgeçici bir nesne üretmez, ancak 'x' değerini artırır ve sonucu ifadeye iletir.

Değer operatörü bilenler için kolaylık sağlıyor.

Örneğin:

int x = 1;
foo(x++); // == foo(1)
// x == 2: true

x = 1;
foo(++x); // == foo(2)
// x == 2: true

Tabii ki, bu örneğin sonuçları diğer eşdeğer (ve belki de daha az eğik) kodundan üretilebilir.

Peki neden postfix operatörümüz var? Sanırım açık bir şekilde yarattığı karışıklığa rağmen, süren bir deyim çünkü. Bir zamanlar değere sahip olduğu algılanan eski bir yapı olsa da, algılanan değerin kolaylık açısından performans için çok fazla olduğundan emin değilim. Bu kolaylık kaybedilmedi, ancak operatörün amacının sorgulanmasıyla sonuçlanan okunabilirlik takdirinin arttığını düşünüyorum.

Artık postfix operatörüne ihtiyacımız var mı? Muhtemelen hayır. Bunun sonucu kafa karıştırıcı ve anlaşılabilirliğe engel teşkil ediyor. Bazı iyi kodlayıcılar, onu kesinlikle nerede bulacağını, özellikle de kendine özgü bir "PERL-esque" güzelliğine sahip olan yerlerde hemen bileceklerdir. Bu güzelliğin maliyeti okunabilirliktir.

Açık kodun açıklık, okunabilirlik, anlaşılabilirlik ve bakım açısından faydaları olduğuna katılıyorum. İyi tasarımcılar ve yöneticiler bunu ister.

Bununla birlikte, bazı programcıların, güzel post prodüksiyon operatörleri gibi bazı şeylerle kod üretmelerini teşvik eden, postfix operatörü gibi, hangi kodu başka türlü hiç düşünmeyecekleri veya entelektüel olarak uyarıcı buldukları belli bir güzellik vardır. Özürlülüğü rağmen, arzu edilmese de onu daha güzel kılan kesin bir şey var.

Başka bir deyişle, bazı insanlar while (*dst++ = *src++);basitçe daha güzel bir çözüm buluyor , basitliği ile nefesinizi kesen bir şey, sanki tuvale fırçalıyormuş gibi. Güzelliği takdir etmek için dili anlamak zorunda kalmanız, yalnızca ihtişamını arttırır.


3
+1 "bazı insanlar sürebilirken (* dst ++ = * src ++); daha güzel bir çözüm olabilir". Kesinlikle. Assembly dilini anlamayan insanlar gerçekten C'nin ne kadar zarif olabileceğini anlamıyorlar, ancak bu kod ifadesi parlayan bir yıldız.
Tin Man

"Artık postfix operatörüne ihtiyacımız var mı? Muhtemelen hayır." - Turing makinelerini düşünmeye yardım edemiyorum. Biz hiç otomatik değişkenler, ihtiyaç mı foraçıklamada, halt, hatta while(elimizdeki gotosonuçta,)?

@ Bernd: Ha! Kapanışları düşünün! Kapaklar! Skandal! lol
Brian M. Hunt

Kapaklar! Ne kadar saçma. Bana bir kaset ver! Cidden, demek istediğim, bir özelliğe ihtiyaç duymadığım / bir özelliğe sahip olduğumun temel karar kriteri olması gerektiğidir (tasarım yapmak, lisp söylemek istemediğiniz sürece). IME Postfix işleçlerini neredeyse sadece kullanıyorum (nay, need ) ve bunun yerine sadece önek olana ihtiyacım var.

2

Kernighan & Ritchie orijinal gerekçesine bakalım (orijinal K&R sayfa 42 ve 43):

Olağandışı yönleri ise ++ ve - ya önek ya da posta eki olarak kullanılabilir. (...) Hiçbir değerin istenmediği bağlamda (..) zevkinize göre önek veya posta ekini seçin. Ancak htere, birinin ya da diğerinin özel olarak çağrıldığı durumlar.

Metin, " daha küçük " kod yazmanın açıkça hedefiyle, dizin içindeki artışları kullanan bazı örneklerle devam eder . Dolayısıyla bu operatörlerin arkasındaki sebep daha kompakt kodların rahatlığıdır.

Verilen üç örnek ( squeeze(), getline()ve strcat()) , dizin oluşturmayı kullanan ifadeler içinde yalnızca posta ekini kullanır. Yazarlar kodu, gömülü artışları kullanmayan daha uzun bir sürümle karşılaştırır. Bu, odaklamanın kompaktlık olduğunu doğrular.

K&R, sayfa 102'de bu operatörlerin işaretçi referans göstermeyle birlikte kullanılmasını vurgulamaktadır (örn. *--pVe *p--). Başka bir örnek verilmemiştir, ancak yine de, faydaların küçüklük olduğunu açıkça belirtmektedirler.

Ön ek, örneğin, bir dizini veya uçtan bakan bir işaretçiyi azaltırken çok yaygın olarak kullanılır.

 int i=0; 
 while (i<10) 
     doit (i++);  // calls function for 0 to 9  
                  // i is 10 at this stage
 while (--i >=0) 
     doit (i);    // calls function from 9 to 0 

1

Ben öncül katılmıyorum gidiyorum ++p, p++nasılsa okunması zor veya belirsiz. Biri "p artış ve ardından p oku", diğeri "p ve ardından p artış" anlamına gelir. Her iki durumda da, koddaki operatör tam olarak kodun açıklamasında yer almaktadır, bu nedenle ne ++anlama geldiğini biliyorsanız, sonuç kodunun ne anlama geldiğini de bilirsiniz.

Sen kullanarak Karartılmış kodu oluşturabilir herhangi bir sözdizimi, ama bu burada bir dava görmüyorum p++/ ++polduğu doğal şaşırtmalı.


1

bu bir elektrik mühendisinin POV'sundan:

Son bir ilk giren ilk (LIFO) yığınının muhafaza edilmesi amacıyla yerleşik artma ve azaltma öncesi operatörleri olan birçok işlemci vardır.

gibi olabilir:

 float stack[4096];
 int stack_pointer = 0;

 ... 

 #define push_stack(arg) stack[stack_pointer++] = arg;
 #define pop_stack(arg) arg = stack[--stack_pointer];

 ...

bilmiyorum, ama hem önek hem de sonek artış işleçlerini görmeyi beklememin nedeni budur.


1

Christophe'nin kompaktlık konusundaki amacının altını çizmek için, size V6'dan bazı kodları göstermek istiyorum. Bu, orijinal C derleyicisinin bir parçasıdır, http://minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/source/c/c00.c :

/*
 * Look up the identifier in symbuf in the symbol table.
 * If it hashes to the same spot as a keyword, try the keyword table
 * first.  An initial "." is ignored in the hash.
 * Return is a ptr to the symbol table entry.
 */
lookup()
{
    int ihash;
    register struct hshtab *rp;
    register char *sp, *np;

    ihash = 0;
    sp = symbuf;
    if (*sp=='.')
        sp++;
    while (sp<symbuf+ncps)
        ihash =+ *sp++;
    rp = &hshtab[ihash%hshsiz];
    if (rp->hflag&FKEYW)
        if (findkw())
            return(KEYW);
    while (*(np = rp->name)) {
        for (sp=symbuf; sp<symbuf+ncps;)
            if (*np++ != *sp++)
                goto no;
        csym = rp;
        return(NAME);
    no:
        if (++rp >= &hshtab[hshsiz])
            rp = hshtab;
    }
    if(++hshused >= hshsiz) {
        error("Symbol table overflow");
        exit(1);
    }
    rp->hclass = 0;
    rp->htype = 0;
    rp->hoffset = 0;
    rp->dimp = 0;
    rp->hflag =| xdflg;
    sp = symbuf;
    for (np=rp->name; sp<symbuf+ncps;)
        *np++ = *sp++;
    csym = rp;
    return(NAME);
}

Bu, samizdat'ta iyi bir eğitim tarzı olarak aktarılan koddur ve bugün onu asla böyle yazmayız. Kaç tane yan etkinin paketlendiğine ifve whilekoşullarına ve bunun tersine, her iki fordöngünün de bir artış ifadesine sahip olmadığına bakın, çünkü bu döngü gövdesinde yapıldı. Kesinlikle gerekli olduğunda blokların yalnızca diş tellerine nasıl sarıldığına bakın.

Bunun bir kısmı kesinlikle derleyicinin bugün bizim için yapmasını beklediğimiz türün manuel olarak mikro-optimizasyonuydu, ancak aynı zamanda bilgisayara tüm arayüzünüzün tek bir 80x25 cam tty olması durumunda kodunuzu istediğinizi öne süreceğim hipotezini ileri süreceğim . mümkün olduğu kadar yoğun olması için aynı anda daha fazlasını görebilirsiniz.

(Her şey için küresel tampon kullanımı, muhtemelen montaj dilinde dişlerini kesmekten bir kalıntıdır.)


Dikkatli kullanın: "ihash = + * sp ++;" Bir noktada C sadece + = değil, aynı zamanda = + işlecine sahipti. Bugün, = + bir atama işlecidir, bunu bir şey yapmaz ve ardından hiçbir şey yapmaz, bu nedenle "ihash = * sp; sp + = 1;"
gnasher729

@ gnasher729 Evet ve daha sonra rp->hflag =| xdflg, modern bir derleyicide sözdizimi hatası olacağına inanıyorum. "Bir noktada" tam olarak V6, olduğu gibi; +=V7'de forma geçiş süreci gerçekleşti. (V6 derleyicisi yalnızca=+ bu kodu doğru okuduğumda kabul etti - aynı dosyadaki () sembolüne bakın.)
zwol 28:16

-1

Belki de kozmetik hakkında da düşünmelisin.

while( i++ )

tartışmasız "daha iyi görünüyor"

while( i+=1 )

Bazı nedenlerden dolayı, artış sonrası operatör çok çekici görünüyor. Kısa, tatlı ve her şeyi 1 arttırır.

while( ++i )

"geriye bakar" değil mi? Birinin olumlu ( +0veya böyle bir şey) olduğunu belirtmekle aptal olması dışında, matematikte İLK işareti asla bir artı görmezsiniz . NESNE + BİR ŞEYİ görmeye alışkınız

Notlandırmayla ilgili bir şey mi var? A, A +, A ++? Size söyleyebilirim ki, Python halkının operator++kendi dillerinden çıkardığı ilk başlarda çok sevimliydim !


1
Örneklerin aynı şeyi yapmıyor. i++orijinal değerini döndürür ive i+=1ve artı 1'in ++iorijinal değerini idöndürür. Kontrol akışı için dönüş değerlerini kullandığınız için bu önemlidir.
David Thornley

Evet haklısın. Ama burada sadece okunabilirliğe bakıyorum.
bobobobo

-2

9'dan 0'a kadar geriye sayım:

for (unsigned int i=10; i-- > 0;)  {
    cout << i << " ";
}

Veya döngü sırasındaki eşdeğeri.


1
Nasıl hakkında for (unsigned i = 9; i <= 9; --i)?
fredoverflow
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.