(yanlış) yaparken {…} yap


125

Bir kişinin bazı kodlarına bakıyordum ve işlevlerinde bir kalıba sahip olduğunu fark ettim:

<return-type> function(<params>)
{
 <initialization>

 do
 {
   <main code for function>
 }
 while(false);

 <tidy-up & return>
}

Fena değil , daha tuhaf (gerçek kod oldukça düzgün ve şaşırtıcı değil). Bu daha önce gördüğüm bir şey değil ve bunun arkasında herhangi bir mantık düşünebilecek biri olup olmadığını merak ettim - farklı bir dilde arka plan olabilir mi?


2
Bunu "normal" sürüme değiştirmeyi ve hala derlenip derlenmediğini görmeyi denediniz mi? Normal olarak yazıldığında derleme yapamazsa, derleyici hatası bunun neden yapıldığına dair bir ipucu verebilir.
Mark Byers

11
Neden bizden niyetiyle ilgili tahminler sormak yerine "bireye" sormuyorsunuz?

1
Belki de profesörü a kullanmasını istedi do...while()ve o zamandan beri bu kodu bir işlev şablonu olarak kullandı.
Hogan

6
@Neil ... Onunla yüzleştiğimde aptal görünmekten kaçınmak istiyorum ve hiç düşünmediğim süper gelişmiş C ++ kullanımını açıklıyor.
Bay Boy

6
Şimdiden epeyce farklı cevaplar var gibi görünüyor, orijinal yazara niyetlerinin ne olduğunu sorabilir ve geri gönderebilir misiniz?
nevets1219

Yanıtlar:


175

Şunları yapabilirsiniz breaküzerinden do{...}while(false).


95
+1 çünkü muhtemelen kodun amacı budur, ancak bunun gibi bir şey yapmak sadece aptalca gizlenmiş bir harekettir. Bir
gitmenin

56
Kılık değiştirmiş bir gitmekten daha fazlası. Kısıtlı (yapılandırılmış) bir gitmedir.
Thomas Eding

19
Ne şekilde "kısıtlanmış"? Sadece ileriye atlamak bir "kısıtlama" değildir. Bir goto bir goto'dur ve birini o değilmiş gibi göstermek için giydirmek, ilk etapta bir goto kullanmaktan daha kötüdür.
Anon.

45
@Anon .: İleriye doğru zıplamak, bir goto için bir kısıtlamadır ve dışarı atlamak kesinlikle bir kısıtlamadır. Gotos'la ilgili gerçek sorun spagetti kodudur ve ileri ve dışarı atlama bunu büyük ölçüde sınırlar.
David Thornley

33
Gerçek bir döngü anlamsal olarak bir goto değildir. Koşullu, anlamsal olarak bir goto değildir. "İşlevinin sonuna git ve temizleme kodu yapmak" olduğunu semantik bir git. Anlambilim uygulandığında gotos kullanın, anlamsal olarak farklı bir şey giydirmeyin çünkü onlardan korkuyorsunuz.
Anon.

126

Pek çok insan bunun genellikle "goto" yazmanın garip bir yolu olarak break ile kullanıldığına dikkat çekiyor. Doğrudan işlevde yazılırsa bu muhtemelen doğrudur.

Bir makroda, OTOH, makro çağrıldıktan do { something; } while (false)sonra noktalı virgülü ZORLAMAK için uygun bir yoldur, kesinlikle başka hiçbir simgenin izlenmesine izin verilmez.

Ve bir başka olasılık da, ya bir kez bir döngü olması ya da gelecekte yinelemenin eklenmesinin beklenmesidir (örneğin, test odaklı geliştirmede, testleri geçmek için yinelemeye gerek yoktu, ancak mantıksal olarak orada döngü yapmak mantıklı olacaktır. işlevin şu anda gerekenden biraz daha genel olması gerekiyordu)


18
Makrolarda bunun faydasından bahsetmek için +1; Kimsenin bundan bahsetmediğine şaşırdım!
Nick Meyer

7
Evet, makro şey aslında bunun tamamen geçerli bir kullanımı. Tabii ki, makroların dışında, sadece aptalca ...;)
jalf

12
Garip değil, kullanışlıdır, çünkü bu bir Kapsamlı goto - do döngüsünde bildirdiğiniz tüm değişkenlerin yok edildiği, oysa goto bunu yapmadığı anlamına gelir.
Ana Betts

9
@Paul: Bu davranışı goto ile zorlamak için bir grup ifadenin etrafına parantez eklemenizi engelleyen hiçbir şey yoktur.
erikkallen

5
@Paul: bir bloktan çıkma, çoğunlukla yerel değişkenlerin break gibi C ++ 'da yok edilmesine neden olur. Ve C değişkenlerinde gerçekten yok edilmez, yığın alanları basitçe geri kazanılır.
Ben Voigt

25

Goto olarak mola muhtemelen cevaptır, ancak bir fikir daha ortaya koyacağım.

Belki yerel olarak tanımlanmış değişkenlere sahip olmak istedi ve bu yapıyı yeni bir kapsam elde etmek için kullandı.

Unutmayın, son C ++ {...}her yere izin verirken , bu her zaman böyle değildi.


30
Bu durumda sadece kaşlı tel kullanabilirdi.
Nemanja Trifunovic

2
@Nemanja, kaç geliştiricinin bunu bilmediğine ve Hogan'ın önerdiği şeyle ilgili bir şeyler denediğine
şaşıracaksınız

8
Sana yeni bir yerel kapsam oluşturabilir anladım o 4 yıl gibi C / C ++ programlama olmuştu til @Polaris @Nemanja, değildi {} hiçbir yerinde .. Bu özellikle kullanışlı switch-casekod
Earlz

1
@Nemanja: Tam olarak ne zaman olduğunu bilmiyorum ama eminim {...}her yer C ++ 'da daha modern bir gelişme (kullandığım ilk C ++' ın bir ön işlemciyle uygulandığını ve bu modern kullanıma izin vermediğini hatırlayın.) Belki yazar çok eski kafalıydı.
Hogan

2
Ne zaman her yerde diş tellerine izin vermedi? 15 yıl önce programlamaya başladım ve o zaman izin verildi (hem ders kitabımda hem de denediğim her derleyicide).
erikkallen

20

İşlev için birçok potansiyel çıkış noktası olduğunda bunun yararlı bir model olarak kullanıldığını gördüm, ancak işlevin nasıl çıktığına bakılmaksızın aynı temizleme kodu her zaman gereklidir.

Bir çıkış noktasına ulaşıldığında, mantığın geri kalanı daha sonra satır içi olacak şekilde, bir çıkış noktasına ulaşıldığında kırılmak zorunda kalındığında, eğer / değilse-if ağacının okunması çok daha kolay yorucu hale getirebilir.

Bu kalıp, goto ifadesi olmayan dillerde de kullanışlıdır. Belki de orijinal programcının kalıbı öğrendiği yer burasıdır.


15
O zaman, ince bir şekilde gizlenmiş bir yol yerine dürüst ve açık bir yol kullanın.
dsimcha

4
Bu yolu daha çok seviyorum. Okuması kolaydır ve bir goto damgasını taşımaz.
Cameron

8
gotos, idareli ve yerel olarak kullanılırsa okunması son derece kolaydır. Akış kontrolünün ana biçimi olduklarında ve yüzlerce çizginin üzerinden atlarken damgalanmalarını geri aldılar.
dsimcha

13
Bir "damgalama" nedeniyle goto kullanmamak, kargo kült programlamasının kesin bir işaretidir.
Anon.

6
Bir yığın temizleme kodunun kötü bir koku olduğundan bahsetmiyorum bile. Bu C ++ olduğundan, temizleme kodu normalde RAII işlemi sırasında çağrılan yıkıcılarda olmalıdır.
David Thornley

12

breakBir gotoçeşit kullanabilmeniz için böyle bir kod gördüm .


10

Bu sadece goto kelimesini kullanmadan whilesematiği elde etmek için yapılan bir sapkınlıktır goto tidy-up.

Kullandığınızda çünkü kötü formudur diğer dış iç döngüler okuyucuya belirsiz hale gelir. "Bunun çıkışa gitmesi mi gerekiyor? Yoksa bu sadece iç döngüden çıkmak mı?"whilebreaks


10

Bence yazmak breakyerine daha uygun goto end. Niyeti daha açık hale getiren etiket için bir isim bile düşünmenize gerek yok: Belirli bir isimle bir etikete atlamak istemezsiniz. Buradan çıkmak istiyorsun.

Ayrıca muhtemelen diş tellerine ihtiyacınız olacak. İşte do{...}while(false);versiyon bu:

do {
   // code
   if (condition) break; // or continue
   // more code
} while(false);

Ve kullanmak istiyorsanız bunu ifade etmeniz gereken yol budur goto:

{
   // code
   if (condition) goto end;
   // more code
}
end:

İlk versiyonun anlamını kavramanın çok daha kolay olduğunu düşünüyorum. Ayrıca yazmak daha kolay, genişletmesi daha kolay, desteklemeyen bir dile çevirmesi daha kolay gotovb.


Kullanımıyla ilgili en sık dile getirilen endişe break, kötü bir şekilde gizlenmiş olmasıdır goto. Ama aslında breakşuna daha çok benziyor return: Her iki komut da, kıyaslandığında hemen hemen yapılandırılmış olan bir kod bloğundan atlar goto. Bununla birlikte, her iki komut da bazen kafa karıştırıcı olabilen bir kod bloğunda birden çok çıkış noktasına izin verir. Sonuçta, özel durumda ne olursa olsun, en net çözümü bulmaya çalışırdım.


Oh, cevap vermeden önce soruyu tamamen anlamadığımı fark ettim. do{ ... }while(false);Genel olarak kullanımıyla ilgili olduğunu düşündüm . Ama aslında onu bir çeşit taklit etmek için kullanmakla ilgili try{ ... }finally{ ... }.
Robert

Gitmek yerine kırılma ve dönüş arasındaki paralelliğin güzel gözlemi. En net çözümün en iyisi olduğu konusunda hemfikir olun. Çoğu durumda, kodu, break yerine return kullanan kendi ayrı işlevinde bu şekilde kapsüllemek ve ardından temizleme işlemini çağıran işlevde yapmak daha açıktır.
2018

7

Bu numara, gotokodlarında açık bir ifade kullanmak için çok utangaç olan programcılar tarafından kullanılır . Yukarıdaki kodun yazarı, kodun ortasından doğrudan "temizleme ve geri dönme" noktasına atlama yeteneğine sahip olmak istedi. Ancak bir etiket ve açık kullanmak istemediler goto. Bunun yerine, breakaynı etkiyi elde etmek için yukarıdaki "sahte" döngünün gövdesinde bir iç kullanabilirler .


7

Bu çok yaygın bir uygulamadır. Olarak . Kendinize "a kullanmıyorum" şeklinde yalan söylemek istiyormuşsunuz gibi düşünmeye çalışıyorum goto. Bunu düşündüğümüzde, gotobenzer şekilde kullanılan bir şeyde yanlış bir şey olmazdı . Aslında girinti seviyesini de azaltacaktır.

Bununla birlikte, fark ettim ki, çoğu zaman bu do..whiledöngüler büyüme eğilimindedir. Ve sonra ifs ve elses içeriye girerek, kodu test edilebilir bir yana, aslında çok okunaklı hale getirmiyorlar.

Bunlar do..whilenormalde temizlik yapmaya yöneliktir . Mümkün Elbette ben kullanmayı tercih ediyorum RAII ve erken dönmek bir gelen kısa fonksiyonu. Öte yandan, C , size C ++ ' nın sağladığı kadar kolaylık sağlamaz do..whileve bir temizlik yapmak için en iyi yaklaşımlardan birini yapar.


6

Bir C programcısına benziyor. C ++ 'da, otomatik değişkenler temizlemek için kullandığınız yıkıcılara sahiptir, bu nedenle geri dönüşten önce toparlanması gereken hiçbir şey olmamalıdır. C'de, bu RAII deyimine sahip değildiniz, bu nedenle ortak temizleme kodunuz varsa, ya gotoonu ya da yukarıdaki gibi tek geçişli bir döngü kullanın.

C ++ deyimiyle karşılaştırıldığında temel dezavantajı, vücuda bir istisna atılırsa toparlanmamasıdır. C'nin istisnaları yoktu, bu yüzden bu bir problem değildi, ancak C ++ 'da kötü bir alışkanlık haline getiriyor.


4

Birkaç açıklama. Birincisi geneldir, ikincisi ise parametrelere sahip C önişlemci makrolarına özeldir:

Akış kontrolü

Bunun düz C kodunda kullanıldığını gördüm. Temel olarak, goto'nun daha güvenli bir sürümüdür, çünkü ondan çıkabilirsiniz ve tüm bellek düzgün bir şekilde temizlenir.

Neden böyle bir şey gotoiyi olsun? Her çizgi bir hata döndürebilir hemen hemen kuralların var ama hepsini aynı şekilde tepki gerekiyorsa Eh, (örneğin teslim temizlemeye sonra arayana hata ile), bir önlemek için genellikle daha okunabilir var if( error ) { /* cleanup and error string generation and return here */ }olduğu temizleme kodunun tekrarlanmasını önler.

Bununla birlikte, C ++ 'da tam olarak bu amaç için istisnalar + RAII var, bu yüzden kötü kodlama stili olduğunu düşünürdüm.

Noktalı virgülle kontrol

Fonksiyon benzeri bir makro çağırmadan sonra noktalı virgülü unutursanız, bağımsız değişkenler istenmeyen bir şekilde daralabilir ve geçerli sözdiziminde derlenebilir. Makroyu hayal edin

#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");

Buna yanlışlıkla denir

if( foo )
    PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
    doSomethingElse();

"Diğer" ile ilişkili olarak kabul edilecek gDebugModeOn, yani olduğu zaman foo, falseamaçlananın tam tersi gerçekleşecektir.

Geçici değişkenler için bir kapsam sağlamak.

Do / while küme parantezi içerdiğinden, geçici değişkenlerin açıkça tanımlanmış kapsamı vardır ve kaçamazlar.

"Muhtemelen istenmeyen noktalı virgül" uyarılarından kaçınma

Bazı makrolar yalnızca hata ayıklama yapılarında etkinleştirilir. Onları şöyle tanımlıyorsunuz:

#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n) 
#endif

Şimdi, bunu bir koşullu içinde bir sürüm yapısında kullanırsanız,

if( foo )
    ;

Birçok derleyici bunu şu şekilde görür:

if( foo );

Genellikle yanlışlıkla yazılır. Yani bir uyarı alırsınız. Do {} while (false) bunu derleyiciden gizler ve burada gerçekten hiçbir şey yapmak istemediğinizin bir göstergesi olarak kabul edilir .

Koşullu satırların yakalanmasından kaçınmak

Önceki örnekten makro:

if( foo )
    DBG_PRINT_NUM(42)
doSomething();

Şimdi, bir hata ayıklama yapısında, alışılmış bir şekilde noktalı virgülü de eklediğimiz için, bu gayet iyi derlenir. Bununla birlikte, sürüm yapısında bu aniden şuna dönüşür:

if( foo )

doSomething();

Veya daha net biçimlendirilmiş

if( foo )
    doSomething();

Hangi hiç amaçlanmadı. Makronun etrafına bir do {...} eklenmesi (false) eksik noktalı virgülü bir derleme hatasına dönüştürür.

Bu, OP için ne anlama geliyor?

Genel olarak, hata işleme için C ++ 'da istisnaları ve makrolar yerine şablonları kullanmak istersiniz. Bununla birlikte, makrolara hala ihtiyaç duyduğunuz (örneğin, simge yapıştırmayı kullanarak sınıf adları oluştururken) veya düz C ile sınırlı olduğunuz çok nadir durumlarda, bu yararlı bir kalıptır.


Kapsam belirlemeye gelince, döngü aparatına ihtiyacınız yoktur; Bir "süssüz" blok yasaldır: x =1; y = 2; { int tmp = y; y = x; x = tmp; }.
chepner

Süslenmemiş bir blok, eksik bir noktalı virgülün varlığını zorlamaz, bu da istenmeyen yan etkilere neden olabilir. Yaparken(); Noktalı virgül GEREKTİRİR ve bu nedenle örn. Yukarıdaki örnekte olduğu gibi, makro bir yayın yapısında hiçbir şey tanımlamıyorsa, aşağıdaki ifadelerin bir "eğer" içine çekilmesine neden olmaz.
uliwitness

Makro için daha iyi bir tanım sağlayarak bundan kaçınılamaz mı? #define DBG_PRINT_NUM(n) {}.
chepner

1
Hayır, çünkü {} tam bir ifadedir, yani ";" ile eşdeğerdir. Yani yazarsanız if(a) DBG_PRINT_NUM(n); else other();derlemez. Yalnızca if(a) {} else other();veya if(a) ; else other();geçerlidir, ancak if(a) {}; else other();değildir, çünkü bu "if" cümlesinin iki ifadeden oluşmasına neden olur.
uliwitness

2

Belki breakde herhangi bir noktada daha fazla kodun yürütülmesini iptal etmek için içeride kullanılabilmesi için kullanılır:

do {
    if (!condition1) break;
    some_code;
    if (!condition2) break;
    some_further_code;
    // …
} while(false);

7
Bunu yapmak, gotosırf birisi "kötü" olduğunu duyduğu için kullanmaktan kaçınma girişimi gibi görünüyor .
Anon.

1
Belki, ancak C ++ 'ın bu nedenle istisnaları vardır.
TED

2

Sanırım bu kullanmak breakveya continueifadeler kullanmak için yapılır . Bir tür "git" kod mantığı.


2

Çok basit: Görünüşe göre, breakifadeyi kullanarak herhangi bir zamanda sahte döngüden atlayabilirsiniz . Dahası, doblok ayrı bir kapsamdır ( { ... }sadece ile de elde edilebilir ).

Böyle bir durumda, RAII kullanmak daha iyi bir fikir olabilir (işlev sona erdiğinde nesneler otomatik olarak doğru şekilde yok edilir). Bir başka benzer yapı da kullanımıdır goto- evet, kötü olduğunu biliyorum , ancak şu şekilde ortak temizleme koduna sahip olmak için kullanılabilir:

<return-type> function(<params>)
{
 <initialization>

 <main code for function using "goto error;" if something goes wrong>

 <tidy-up in success case & return>

 error:

 <commmon tidy-up actions for error case & return error code or throw exception>
}

(Bir kenara: Do-while-false yapısı, Lua'da eksik continueifadeyi bulmak için kullanılır.)


2

Cevap verenlerin çoğu bunun sebebini verdi do{(...)break;}while(false). Resmi bir başka gerçek hayattan örnekle tamamlamak istiyorum.

Aşağıdaki kodda operation, dataişaretçi tarafından gösterilen adrese göre numaralandırıcıyı ayarlamak zorunda kaldım . Bir anahtar durumu yalnızca skaler türlerde kullanılabildiğinden, ilk önce bunu verimsiz bir şekilde bu şekilde yaptım

if (data == &array[o1])
    operation = O1;
else if (data == &array[o2])
    operation = O2;
else if (data == &array[on])
    operation = ON;

Log("operation:",operation);

Ancak Log () ve kodun geri kalanı seçilen herhangi bir işlem değeri için tekrarladığından, adres zaten keşfedildiğinde geri kalan karşılaştırmaları nasıl atlayacağımı merak ediyordum. Ve işte burada do{(...)break;}while(false)işe yarıyor.

do {
    if (data == &array[o1]) {
        operation = O1;
        break;
    }
    if (data == &array[o2]) {
        operation = O2;
        break;
    }
    if (data == &array[on]) {
        operation = ON;
        break;
    }
} while (false);

Log("operation:",operation);

Aşağıdakiler gibi breakbir ififadede neden aynı şeyi yapamadığı merak edilebilir :

if (data == &array[o1])
{
    operation = O1;
    break;
}
else if (...)

breakyalnızca en yakın kapsayan ile etkileşimde döngü bir olsun veya switch, for, whileveya do .. whilebu nedenle maalesef bu işe olmaz, türü.


1

Yazar kaç yaşındaydı?

Soruyorum çünkü 80'lerin sonunda bunu yapan gerçek zamanlı bir Fortran koduyla karşılaşmıştım. Bu, onlara sahip olmayan bir işletim sisteminde iş parçacıklarını simüle etmenin gerçekten iyi bir yolu olduğu ortaya çıktı. Sadece tüm programı (zamanlayıcınızı) bir döngüye koyarsınız ve "iş parçacığı" yordamlarınızı "birer birer çağırırsınız. İş parçacığı rutinlerinin kendileri, bir dizi koşuldan biri gerçekleşene kadar yinelenen döngülerdir (genellikle biri belirli bir miktarda Zaman geçti). Bu "işbirliğine dayalı çoklu görevdir", çünkü CPU'dan ara sıra vazgeçmek bireysel iş parçacıklarına bağlıdır, böylece diğerleri açlıktan ölmez. İş parçacığı önceliğini simüle etmek için döngü alt program çağrılarını iç içe yerleştirebilirsiniz. bantlar.



0

Pek çok postere, ince gizlenmiş bir yol olarak kullanımı hakkında katılıyorum. Tarzda kod yazmak için potansiyel bir motivasyon olarak makrolardan da bahsedilmiştir.

Bu yapının karışık C / C ++ ortamlarında fakir bir adamın istisnası olarak kullanıldığını da gördüm. Bir "break" ile "do {} while (false)", normalde döngüde bir istisnayla karşılaşılması durumunda kod bloğunun sonuna atlamak için kullanılabilir.

"İşlev başına tek getiri" ideolojisinin uygulandığı mağazalarda kullanılan bu yapıyı da benimsedim. Yine, bu açık bir "git" yerine - ancak motivasyon birden fazla dönüş noktasından kaçınmak, kodu "atlamak" ve o işlev içinde fiili çalışmaya devam etmek değil.


0

Adobe InDesign SDK ile çalışıyorum ve InDesign SDK örneklerinde hemen hemen her işlevi bu şekilde yazılıyor. Bunun nedeni, işlevin genellikle gerçekten uzun olmasıdır. Uygulama nesne modelinden herhangi bir şey almak için QueryInterface (...) yapmanız gereken yer. Bu nedenle, genellikle her QueryInterface ardından ifiyi gitmedi, kırılır.


0

Birçoğu bu yapı ile a arasındaki benzerliği zaten belirtmiş gotove goto için bir tercih belirtmiştir . Belki de bu kişinin geçmişi, kodlama yönergeleri ile goto'ların kesinlikle yasaklandığı bir ortamı içeriyordu?


0

Aklıma gelen diğer bir neden ise diş tellerini süslüyor olması, oysa daha yeni bir C ++ standart çıplak diş tellerinin uygun olmadığına inanıyorum (ISO C onlardan hoşlanmıyor). Aksi takdirde, statik bir analizörü tüy gibi susturmak için.

Bunları neden istediğinizden emin değilim, belki değişken kapsam veya bir hata ayıklayıcı ile avantaj.

Bakın Önemsiz Yaparken Döngüsü ve C2'den Küme Ayraçları İyi .

Terminolojimi netleştirmek için (standart kullanımı takip ettiğine inanıyorum):

Çıplak diş telleri :

init();
...
{
c = NULL;
mkwidget(&c);
finishwidget(&c);
}
shutdown();

Boş parantezler (NOP):

{}

Örneğin

while (1)
   {}  /* Do nothing, endless loop */

Engelle :

if (finished)
{
     closewindows(&windows);
     freememory(&cache);
}

hangisi olur

if (finished)
     closewindows(&windows);
freememory(&cache);

küme parantezleri kaldırılırsa, sadece yerel değişkenlerin kapsamını değil, yürütme akışını da değiştirir. Bu nedenle 'bağımsız' veya 'çıplak' değil.

Kodun herhangi bir bölümünü belirtmek için çıplak parantezler veya bir blok, işaretlemek istediğiniz (satır içi) işlev için potansiyel olabilecek ancak o anda yeniden düzenleme yapmayacağınızı belirtmek için kullanılabilir.


Gerçekten mi? Bu utanç verici. C ile ilgili sevdiğim birkaç şeyden biri, hemen her yerde yeni bir iç içe geçmiş kapsam bildirmenize izin vermesiydi.
TED

1
Çıplak diş telleri bazen garip kazaları düzeltmeye yardımcı olur. Blogs.msdn.com/oldnewthing/archive/2004/05/20/135841.aspx sayfasına bakın .
Brian

1
C ++ 'da, bir blok (yani "çıplak parantezleriniz") tek bir ifadeye izin verilen her yerde kullanılabilir.
Ben Voigt

@BenVoigt Boş küme parantezleri, yani bir NOP, doğrusal bir talimat dizisi etrafına eklenen bir blok olan "çıplak parantezlerden" farklıdır. Örneğin `printf (" Merhaba "); {putchar (','); putchar (0x20); } printf ("dünya! \ n"); `buradaki küme parantezleri döngü veya dal kontrolünün parçası değildir .
mctylr

@mctylr: Boş diş tellerinden bahsetmiyordum.
Ben Voigt

0

Bu GOTOikisi pratik olarak aynı olduğundan , a'yı taklit etmenin uydurma bir yolu :

// NOTE: This is discouraged!
do {
    if (someCondition) break;
    // some code be here
} while (false);
// more code be here

ve:

// NOTE: This is discouraged, too!
if (someCondition) goto marker;
// some code be here
marker:
// more code be here

Öte yandan, bunların her ikisi de gerçekten ifs ile yapılmalıdır :

if (!someCondition) {
    // some code be here
}
// more code be here

Uzun bir iletme dizisini GOTOiç içe geçmiş ife- postalara çevirirseniz yuvalama biraz çirkinleşebilir . Gerçek cevap, arkaik dil yapılarını taklit etmek değil, uygun şekilde yeniden düzenlemektir.

Eğer çaresizce içinde GOTOs bulunan bir algoritmayı çevirmeye çalışıyorsanız , muhtemelen bu deyimle bunu yapabilirsiniz. Kesinlikle standart dışı ve dilin beklenen deyimlerine sıkı sıkıya bağlı kalmadığınızın iyi bir göstergesi.

Aslında, do / while'ın herhangi bir şey için deyimsel bir çözüm olduğu C benzeri bir dilin farkında değilim.

Muhtemelen tüm dağınıklığı daha deyimsel ve daha okunaklı hale getirmek için daha mantıklı bir şeye dönüştürebilirsiniz.


1
Alan do..while(false)ise değil kez "tanımsız" dizi çalıştırmak için, Çalışıyorsa içindir kez .
Dmitry

2
continueSonunda gösterdiğim gibi koşullu bir ifadeniz varsa, tanımsız sayıda çalıştırıyor . By undefinedI basitçe bunu daha sen koşulların belirli bir tekrarda karşılanacak olup olmadığını tahmin edebilirsiniz sürece kereden çalışıyor bilmiyorum anlamına gelir. continueİçinde herhangi bir s olmadan , bir do..while(false)kez çalışır, ancak aynı zamanda herhangi bir breaks olmadan da while(true)sonsuza kadar çalışır, bu nedenle "varsayılan davranış" döngülerle neler yapılabileceğini anlamak için gerçekten alakalı değildir .
Alan Plum

Birden çok ifadeye sahip bir makro tanımladığınızda kullanışlıdır. Bunları bir do / while (false) içine sararsanız, makroyu diğer herhangi bir işlev çağrısı gibi bir if / else deyiminde kullanabilirsiniz. açıklama için romantheory.com/TechPapers/ while.htm adresine bakın
John Paquin

5
Birisi anlamını anlamıyor continue. continuedöngüyü tekrar ETMEZ. " continueİfade yalnızca bir yineleme deyiminde meydana gelecektir ve denetimin en küçük çevreleyen yineleme ifadesinin döngü devam etme kısmına , yani döngünün sonuna geçmesine neden olur ."
Ben Voigt

-1, @BenVoigt'in işaret ettiği nedenlerle ilk iki ifade aynı değildir.
cmh

0

Bazı kodlayıcılar, işlevlerinden yalnızca tek bir çıkış / dönüşe sahip olmayı tercih eder. Bir kukla kullanımı do {....} while (false); Bitirdiğinizde ve yine de tek bir dönüşünüz olduğunda kukla döngüden "çıkmanıza" olanak tanır.

Ben bir java kodlayıcısıyım, bu yüzden örneğim şöyle bir şey

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class p45
{
    static List<String> cakeNames = Arrays.asList("schwarzwald torte", "princess", "icecream");
    static Set<Integer> forbidden = Stream.of(0, 2).collect(Collectors.toSet());

    public static  void main(String[] argv)
    {
        for (int i = 0; i < 4; i++)
        {
            System.out.println(String.format("cake(%d)=\"%s\"", i, describeCake(i)));
        }
    }


    static String describeCake(int typeOfCake)
    {
        String result = "unknown";
        do {
            // ensure type of cake is valid
            if (typeOfCake < 0 || typeOfCake >= cakeNames.size()) break;

            if (forbidden.contains(typeOfCake)) {
                result = "not for you!!";
                break;
            }

            result = cakeNames.get(typeOfCake);
        } while (false);
        return result;
    }
}


-1

Bu çok eğlenceli. Başkalarının da söylediği gibi döngünün içinde muhtemelen kırılmalar var. Bunu şu şekilde yapardım:

while(true)
{
   <main code for function>
   break; // at the end.
}

2
Sonsuza dek döngü yapma potansiyeli olan mı? do..while(false)her zaman çıkar while(true), daha riskli taraftadır.
Dmitry

1
while(true)çoğu dilde doğru deyimdir. Bunu genellikle GUI uygulamalarında programın ana döngüsü olarak bulacaksınız. Temelde, programın kendisine söylenene kadar ölmemesi gerektiğini varsaydığınız için, do..while(false)her türlü yapmacık mantığa neden olur. Bu yaklaşım, mükemmeliyetçi bir bakış açısına göre daha riskli olabilir, ancak anlamsal olarak daha kolaydır ve bu nedenle insan programcılar için daha az hataya açıktır (üzgünüm, Skynet).
Alan Plum

2
@dmitry do{...}while(false)ile tamamen aynıwhile(true){ .. break;}
N 1.1

4
@ N1.1: Varlığında continuedeğil, aynı değiller.
Ben Voigt
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.