Derleyici kodumu kırdı mı ve derleyici olsaydı ne yapmalıyım?


14

Arada sırada C ++ kodu, bazı optimizasyon düzeyleriyle derlendiğinde çalışmaz. Bu derleyici kodu kıran optimizasyon yapıyor olabilir ya da derleyicinin hissettirdiği her şeyi yapmasına izin veren tanımlanmamış davranış içeren kod olabilir.

Yalnızca daha yüksek optimizasyon düzeyiyle derlendiğinde kesilen bir kod parçam olduğunu varsayalım. Kod veya derleyici olup olmadığını nasıl derlerim ve derleyici ise ne yapmalıyım?


43
Büyük olasılıkla sensin.
littleadv

9
@littleadv, gcc ve msvc'nin son sürümleri bile hatalarla dolu, bu yüzden o kadar emin olmazdım.
SK-logic

3
Tüm uyarıları etkinleştirdiniz mi?

@ Thorbjørn Ravn Andersen: Evet, onları etkinleştirdim.
sharptooth

3
FWIW: 1) Derleyicinin dağılmasını ayarlayabilecek zor bir şey yapmamaya çalışıyorum, 2) optimizasyon bayrakları maddesinin (hız için) tek yeri program sayacının zamanının önemli bir bölümünü geçirdiği kodda. Sıkı işlemci döngüleri yazmadığınız sürece, PC birçok uygulamada esasen tüm zamanlarını kütüphanelerde veya G / Ç'de geçirir. Bu tür uygulamalarda, / O anahtarları size hiç yardımcı olmaz.
Mike Dunlavey

Yanıtlar:


19

Vakaların büyük çoğunluğunda, derleyicinin değil, kodunuzun kırılması güvenli bir bahis olduğunu söyleyebilirim. Ve derleyici olduğu olağanüstü durumda bile, muhtemelen belirli bir derleyicinin hazırlanmadığı bazı belirsiz dil özelliklerini alışılmadık bir şekilde kullanıyorsunuz; başka bir deyişle, kodunuzu daha deyimsel olacak şekilde değiştirebilir ve derleyicinin zayıf noktasından kaçınabilirsiniz.

Her halükarda, bir derleyici hatası bulduğunuzu kanıtlayabilirseniz (dil spesifikasyonuna göre), derleyici geliştiricilerini bildirin, böylece bir süre düzeltilmesini sağlayabilirler.


@ SK-logic, yeterince adil, destekleyecek hiçbir istatistikim yok. Kendi deneyimlerime dayanıyor ve dilin ve / veya derleyicinin sınırlarını nadiren uzattığımı itiraf ediyorum - diğerleri bunu daha sık yapabilir.
Péter Török

(1) @ SK-Logic: Bir C ++ derleyici hatası buldum, aynı kod, bir derleyici üzerinde çalıştı ve çalışıyor, bir diğerinde denedi kırdı.
umlcat

8
@ umlcat: belirtilmemiş davranışa bağlı olarak büyük olasılıkla kodunuzdu; bir derleyicide beklentilerinizle eşleşir, diğerinde değil. bu kırıldığı anlamına gelmez.
Javier

@Ritch Melton, hiç LTO kullandınız mı?
SK-logic

1
Oyun konsolları hakkında konuşurken Crashworks'e katılıyorum. Bu özel durumda ezoterik derleyici hatalarını bulmak hiç de alışılmadık bir durum değil. Bununla birlikte, normal PC'leri hedefliyorsanız, yoğun olarak kullanılan bir derleyici kullanarak, daha önce kimsenin görmediği bir derleyici hatasına girmeniz pek olası değildir.
Trevor Powell

14

Her zamanki gibi, diğer hatalarda olduğu gibi: kontrollü bir deney yapın. Şüpheli alanı daraltın, diğer her şey için optimizasyonları kapatın ve bu kod grubuna uygulanan optimizasyonları değiştirmeye başlayın. % 100 tekrarlanabilirlik elde ettikten sonra, kodunuzu değiştirmeye başlayın ve belirli optimizasyonları kırabilecek şeyler getirin (örn. Olası işaretçi takma adı ekleyin, potansiyel yan etkilerle harici çağrılar ekleyin, vb.). Bir hata ayıklayıcıda derleme koduna bakmak da yardımcı olabilir.


ne ile yardımcı olabilir? Bir derleyici hata ise - ne olmuş yani?
littleadv

2
@littleadv, eğer bir derleyici hatasıysa, düzeltmeyi deneyebilir (veya sadece ayrıntılı olarak düzgün bir şekilde raporlayabilirsiniz) veya bunu kullanmaya devam etmek zorunda kalırsanız gelecekte nasıl önleneceğini öğrenebilirsiniz. Derleyicinizin bir süreliğine. Çok sayıda C ++ - ish sınır çizgisi sorunlarından biri olan kendi kodunuzla ilgili bir şey varsa, bu tür bir inceleme ayrıca bir hatayı düzeltmeye ve gelecekte türünden kaçınmaya yardımcı olur.
SK-logic

Cevabımda söylediğim gibi - raporlama dışında, kimin hatası olduğuna bakılmaksızın tedavide çok fazla fark yok.
littleadv

3
@littleadv, bir sorunun doğasını anlamadan tekrar tekrar karşılaşmanız muhtemeldir. Ve genellikle bir derleyiciyi kendi başınıza düzeltme olasılığı vardır. Ve, evet, ne yazık ki, bir C ++ derleyicisinde bir hata bulmak hiç de olası değildir.
SK-logic

10

Ortaya çıkan montaj kodunu inceleyin ve kaynağınızın ne istediğini yapıp yapmadığını görün. Oranların çok yüksek olduğunu ve bunun açıkça belli olmayan bir şekilde kodunuzun hatalı olduğunu unutmayın.


1
Bu sorunun gerçekten tek cevabı bu. Derleyiciler işi, bu durumda, C ++ 'dan montaj diline götürmektir. Derleyici olduğunu düşünüyorsun ... derleyicilerin çalışmasını kontrol et. Bu kadar basit.
old_timer

7

30 yılı aşkın programlamada, bulduğum gerçek derleyici (kod oluşturma) hatalarının sayısı hala sadece ~ 10. > 10.000. Benim "temel kuralı" benim derleyici nedeniyle verilen herhangi bir hata olasılığı <0.001 olmasıdır.


1
Şanslısın. Ortalamam ayda yaklaşık 1 gerçekten kötü bir hata ve küçük sınır sorunları çok daha sık. Kullandığınız optimizasyon seviyesi ne kadar yüksek olursa, derleyici hata olasılıkları o kadar yüksek olur. -O3 ve LTO'yu kullanmaya çalışıyorsanız, kısa sürede bir çift bulamadığınız için çok şanslı olacaksınız. Ve sadece sürüm sürümlerindeki hataları sayıyorum - bir derleyici geliştiricisi olarak, işimde bu türden çok daha fazla sorunla karşılaşıyorum, ama bu sayılmaz. Bir derleyiciyi vidalamanın ne kadar kolay olduğunu biliyorum.
SK-logic

2
25 yıl ve ben de çok gördük. Derleyiciler her yıl daha da kötüye gidiyor.
old_timer

5

Bir yorum yazmaya başladım ve sonra konuya çok uzun ve çok fazla karar verdim.

Ben kırık kod olduğunu iddia ediyorum. Derleyicide bir hata keşfetmeniz olası olmayan bir durumda - derleyici geliştiricilerine bildirmelisiniz, ancak fark burada sona erer.

Çözüm, rahatsız edici yapıyı tanımlamak ve aynı mantığı farklı şekilde yapması için yeniden düzenleme yapmaktır. Hatanın sizin tarafınızda veya derleyicide olması sorunu büyük olasılıkla çözecektir.


5
  1. Kodunuzu iyice tekrar okuyun. ASSERT'lerde veya diğer hata ayıklama (veya daha genel, yapılandırmaya) özel ifadelerde yan etkileri olan şeyler yapmadığınızdan emin olun. Ayrıca, bir hata ayıklama derlemesinde farklı şekilde başlatıldığını unutmayın - küçük işaretçi değerlerini buradan kontrol edebilirsiniz: Hata ayıklama - Bellek Ayırma Temsilleri . Visual Studio içinden çalıştırırken, açıkça bir ortam değişkeni ile istediğinizi belirtmediğiniz sürece, Debug Heap'ı (yayınlama modunda bile) neredeyse her zaman kullanıyorsunuzdur.
  2. Yapınızı kontrol edin. Gerçek derleyiciden başka yerlerde karmaşık yapılarla ilgili problemler almak yaygındır - bağımlılıklar genellikle suçludur. "Tamamen yeniden inşa etmeyi denediniz mi" neredeyse "pencereleri yeniden yüklemeyi denediniz mi" gibi bir cevabı çileden çıkardığını biliyorum, ama genellikle yardımcı olur. Deneyin: a) Yeniden başlatma. b) Tüm ara ve çıktı dosyalarınızı manuel olarak silme ve yeniden oluşturma.
  3. Tanımsız davranışları çağırıyor olabileceğiniz olası konumları kontrol etmek için kodunuzu inceleyin. Bir süredir C ++ 'da çalışıyorsanız, "Tamamen bunu kabul etmeme izin verildiğinden emin değilim ..." diye düşündüğünüz bazı noktalar olduğunu bileceksiniz. tanımlanmamış davranış olup olmadığını görmek için kod türü.
  4. Durum hala böyle değilse, sorunlara neden olan dosya için önceden işlenmiş çıktı oluşturun. Beklenmedik bir makro genişleme her türlü eğlenceye neden olabilir (Bir iş arkadaşının H adına göre bir makronun iyi bir fikir olacağına karar vermesi hatırlatılır ...). Önceden işlenmiş çıktıyı proje yapılandırmalarınız arasında beklenmedik değişiklikler açısından inceleyin.
  5. Son çare - şimdi gerçekten derleyici hata ülkesindesiniz - montaj çıktısına bakın. Bu, meclisin gerçekte ne yaptığını anlamak için biraz kazma ve kavga gerektirebilir, ancak aslında oldukça bilgilendiricidir. Burada aldığınız becerileri mikro optimizasyonları değerlendirmek için de kullanabilirsiniz, böylece her şey kaybolmaz.

"Tanımsız davranış" için +1. O tarafından ısırıldım. int + intBir donanım ADD komutuna derlenmiş gibi taşmaya bağlı bazı kodlar yazdı . GCC'nin eski bir sürümü ile derlendiğinde iyi çalıştı, ancak daha yeni derleyici ile derlendiğinde işe yaramadı. Görünüşe göre GCC'deki iyi insanlar, tamsayı taşması sonucu tanımlanmadığından, optimize edicilerinin asla gerçekleşmeyeceği varsayımı altında çalışabileceğine karar verdiler. Koddan önemli bir dalı optimize etti.
Solomon Slow

2

Kod veya derleyici olup olmadığını bilmek istiyorsanız, C ++ belirtimini mükemmel bir şekilde bilmeniz gerekir.

Şüphe devam ederse, x86 montajını mükemmel bir şekilde bilmeniz gerekir.

Eğer her ikisini de mükemmelliği öğrenme havasında değilseniz, derleyicinizin optimizasyon seviyesine bağlı olarak farklı şekilde çözdüğü neredeyse kesin olarak tanımlanmamış bir davranıştır.


(+1) @mouviciel: Ayrıca, belirtiminde olsa bile, özellik derleyici tarafından desteklenip desteklenmediğine de bağlıdır. Gcc ile garip bir hata var. Bir "işlev işaretçisi" ile bir "düz c yapısı" beyan, belirtiminde izin verilir, ancak bazı durumlarda çalışır ve başka bir durumda değil.
umlcat

1

Standart kodda derleme hatası veya dahili derleme hatası almak, optimizasyon yapanların yanlış olmasından daha olasıdır. Ama bir yöntem neden bazı yan etkileri unutmadan döngüleri optimize optimize derleyiciler duydum.

Senin ya da derleyicinin olup olmadığını bilmek için hiçbir öneri yok. Başka bir derleyici deneyebilirsiniz.

Bir gün kodum olup olmadığını merak ediyordum ve birisi bana valgrind önerdi. Ben programımı onunla çalıştırmak için 5 veya 10mins geçirdi (ı valgrind --leak-check=yes myprog arg1 arg2did o yaptım ama diğer seçeneklerle oynadı) ve hemen bana sorun olan belirli bir durumda altında koştu bir satır gösterdi. Sonra benim app hiç garip çökmeler, hatalar veya garip davranış ile sorunsuz koştu. valgrind veya bunun gibi başka bir araç, kodunuzun olup olmadığını bilmek için iyi bir yoldur.

Yan not: Bir keresinde uygulamamın performansının neden emildiğini merak ettim. Performans sorunlarımın tek bir satırda olduğu ortaya çıktı. Ben yazdım for(int i=0; i<strlen(sz); ++i) {. Sz birkaç mb oldu. Herhangi bir nedenle derleyici, optimizasyondan sonra bile her seferinde yanık çalıştı. Bir satır önemli olabilir. Performanslardan çökmelere


1

Giderek yaygınlaşan bir durum, derleyicilerin, C tarafından kullanılan ve Standartlar tarafından zorunlu olmayan davranışları destekleyen C lehçeleri için yazılmış kodu kırması ve bu lehçeleri hedefleyen kodun, kesinlikle uyumlu koddan daha verimli olmasına izin vermesidir. Böyle bir durumda, hedef lehçeyi uygulayan derleyicilerde% 100 güvenilir olacak "kırık" kod olarak tanımlamak veya gerekli anlambilimi desteklemeyen bir lehçeyi işleyen derleyiciyi "kırık" olarak tanımlamak haksızlık olur. . Bunun yerine, problemler basitçe, modern derleyiciler tarafından optimizasyonların etkinleştirildiği şekilde işlenen dilin, eskiden popüler olan (ve hala optimizasyonları devre dışı bırakılmış birçok derleyici tarafından veya hatta optimizasyonlar etkinken bile işlenen) lehçelerden sapması gerçeğinden kaynaklanmaktadır.

Örneğin, gcc'nin Standardı yorumlamasıyla zorunlu olmayan bir dizi işaretçi takma desenini meşru olarak tanıyan lehçeler için çok sayıda kod yazılır ve kodun basit bir çevirisinin daha okunabilir ve verimli olmasını sağlamak için bu desenlerden yararlanır. gcc'nin C Standardını yorumlamasıyla mümkün olacaktır. Böyle bir kod gcc ile uyumlu olmayabilir, ancak bu bozuk olduğu anlamına gelmez. Sadece gcc'nin yalnızca optimizasyonlar devre dışı bırakıldığında desteklediği uzantılara dayanır.


C standart X + Y ve Z uzantılarını kodlamanın yanlış bir şey olmadığından emin olun, bu size önemli avantajlar sağladığı sürece bunu yaptığınızı biliyorsunuz ve iyice belgelediniz. Ne yazık ki, her üç koşul da normal olarak karşılanmaz ve bu nedenle kodun bozulduğunu söylemek doğrudur.
Deduplicator

@Deduplicator: C89 derleyicileri öncekilerle yukarı doğru uyumlu ve C99 vb. İçin benzer şekilde tanıtıldı. C89, daha önce bazı platformlarda tanımlanmış ancak diğerlerinde tanımlanmamış davranışlar için herhangi bir gereksinim getirmezken, yukarı uyumluluk C89 derleyicilerinin davranışları tanımlandığı şekilde gören platformlar bunu yapmaya devam etmelidir; kısa imzasız tiplerin işaretlere yükseltilmesinin mantığı, Standardın derleyicilerinin yazarlarının, Standardın zorunlu kılınması gerekip gerekmediği gibi davranmasını beklediğini düşündürmektedir. Dahası ...
Supercat

... diğer adlandırma kurallarının sıkı bir şekilde yorumlanması pencereden yukarı doğru uyumluluk sağlar ve birçok kod türünü işlenemez hale getirir, ancak birkaç ince ayar (örneğin, çapraz tip örtüşme beklenen ve bu nedenle izin verilen bazı kalıpları tanımlamak) her iki sorunu da çözecektir . Kuralın belirtilen tüm amacı, derleyicilerin "karamsar" takma varsayımlarda bulunmalarını istemekten kaçınmaktı, ancak "float x" verildiğinde, "foo ((int *) & x)" ifadesinin "foo" yapmasa bile x'i değiştirebileceği varsayımı 'float * "veya" char * "türündeki herhangi bir göstergeye" kötümser "veya" açık "olarak kabul edilmez mi?
Supercat

0

Sorunlu noktayı izole edin ve gözlenen davranışı dil özelliklerine göre olması gerekenlerle karşılaştırın. Kesinlikle kolay, ama sen yapman gerekeni en etmek değil biliyorum (ve adil değil varsayalım ).

Muhtemelen o kadar titiz olmazdım. Bunun yerine, derleyici üreticisinin destek forumunu / posta listesini soracağım. Derleyicide gerçekten bir hata varsa, o zaman düzeltebilirler. Muhtemelen yine de benim kodum olurdu. Örneğin, iş parçacığındaki bellek görünürlüğü ile ilgili dil özellikleri oldukça mantıklı olabilir ve yalnızca belirli bir donanım (!) Üzerinde bazı özel optimizasyon bayrakları kullanıldığında belirgin hale gelebilir. Bazı davranışlar spec tarafından tanımlanmamış olabilir, bu nedenle bazı derleyici / bazı bayraklarla çalışabilir ve diğerleriyle çalışamaz, vb.


0

Büyük olasılıkla kodunuzun bazı tanımlanmamış davranışları vardır (diğerleri açıkladığı gibi, C ++ derleyicileri hatalara sahip olacak kadar karmaşık olsa bile kodunuzda derleyiciye göre hatalara sahip olma olasılığınız daha yüksektir; C ++ belirtiminde bile tasarım hataları vardır) . Ve UB, derlenmiş yürütülebilir dosya çalışıyor olsa bile (kötü şansla) burada olabilir.

Bu yüzden Lattner'ın blogunu okumalısınız Her C Programcısı tanımlanmamış davranış hakkında ne bilmelidir (çoğu C ++ 11 için de geçerlidir).

Valgrind aracı ve son -fsanitize= enstrümantasyon seçenekleri için GCC (veya Clang / LLVM ) da yararlı olmalıdır. Ve elbette, tüm uyarıları etkinleştirin:g++ -Wall -Wextra

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.