Asla çalıştırılmayacak kod, tanımsız davranışı çağırabilir mi?


81

Tanımlanmamış davranışı çağıran kod (bu örnekte, sıfıra bölme) asla çalıştırılmayacak, program hala tanımsız davranış mı?

Bunun hala tanımlanmamış bir davranış olduğunu düşünüyorum, ancak standartta beni destekleyecek veya reddedecek herhangi bir kanıt bulamıyorum.

Eee, herhangi bir fikrin var mı?


7
Hiç uygulanmazsa bunun "davranış" olmadığını söyleyebilirim
Kevin

1
UB çalışma zamanı birse (bunun gibi) - olmaz. Ama standardın bu konuda bir şey söylediğinden şüpheliyim.
keltar

13
Programlama değil, anlambilim meselesi gibi geliyor.
Wooble

14
@Wooble Katılmıyorum. Tanımlanmamış davranış ifadesinin C / C ++ 'da özel bir anlamı vardır. Ve bu soru, tanımlanmamış davranışı belirleyen veya belirlemeyen diğer bazı durumlarla ilgilidir. Kayıt için, C / C ++ standardını okuduysanız, her yerde tanımsız davranış ifadesini bulacaksınız .
Yu Hao

10
@Cornstalks: C standardı "tanımsız davranışı çağırır" ifadesini kullanmaz, bu nedenle bu cümlenin ne anlama geldiğine bağlı olarak C standardı hakkında mantık yürütemezsiniz. C'yi tanımlamak için kullanmak uygun değildir çünkü “tanımlanmamış davranış” ın sınırların dışına çıktığınızda karşılaşacağınız bir duvar gibi bir şey olduğunu ima eder . Aslında, "tanımlanmamış davranış" bir şeyin eksikliğidir; sınırların sonu. Standart C olan iyi tanımlanmış kasabayı terk ettiğinizde, her şeyin inşa edilebileceği açık bir alandasınız.
Eric Postpischil

Yanıtlar:


71

C standardının "davranış" ve "tanımlanmamış davranış" terimlerini nasıl tanımladığına bakalım.

Referanslar , ISO C 2011 standardının N1570 taslağına; Yayınlanan üç ISO C standardından (1990, 1999 ve 2011) herhangi bir ilgili farkın farkında değilim.

Bölüm 3.4:

davranış
dış görünüş veya eylem

Tamam, bu biraz belirsiz, ancak belirli bir ifadenin "görünüşü" olmadığını ve gerçekten yürütülmedikçe kesinlikle "eylem" olmadığını iddia ediyorum.

Bölüm 3.4.3:


Taşınabilir olmayan veya hatalı bir program yapısının veya hatalı verilerin kullanılması durumunda, bu Uluslararası Standardın herhangi bir gereklilik getirmediği, tanımlanmamış davranış davranışı

Böyle bir yapının " kullanımı üzerine " yazıyor . "Kullanım" kelimesi standart tarafından tanımlanmadığından, ortak İngilizce anlamına geri dönüyoruz. Hiç çalıştırılmazsa bir yapı "kullanılmaz".

Bu tanımın altında bir not var:

Not - Olası tanımlanmamış davranış, durumu tamamen öngörülemeyen sonuçlarla göz ardı etmekten, çevrenin özelliği olan belgelenmiş bir şekilde (bir teşhis mesajı yayınlayarak veya vermeden) çeviri veya program yürütme sırasında davranmaya, bir çeviriyi veya yürütmeyi sonlandırmaya ( bir teşhis mesajının verilmesi).

Dolayısıyla, bir derleyicinin davranışı tanımsız ise derleme zamanında programınızı reddetmesine izin verilir . Ama bu benim yorumlanması o kadar yapabilmesidir sadece o programın her yürütme tanımsız davranış karşılaşacak ispat eğer. Sanırım bu şu anlama geliyor:

kesinlikle hangi edebilirsiniz tanımsız davranışa sahip, derleme zamanında reddedilemez.

Pratik bir mesele olarak, programların tanımsız davranışları harekete geçirmeye karşı koruma sağlamak için çalışma zamanı testleri gerçekleştirebilmesi gerekir ve standardın buna izin vermesi gerekir.

Örneğiniz şuydu:

0 ile bölmeyi asla gerçekleştirmez. Çok yaygın bir deyim:

Bölüm kesinlikle tanımlanmamış davranışa sahiptir y == 0, ancak hiçbir zaman yürütülmez y == 0. Davranış iyi tanımlanmıştır ve örneğinizin iyi tanımlanmasıyla aynı nedenden ötürü: çünkü potansiyel tanımlanmamış davranış aslında asla gerçekleşemez.

(Tabii INT_MIN < -INT_MAX && x == INT_MIN && y == -1(evet, tamsayı bölme aşabilir), ancak bu ayrı bir konudur.

Bir yorumda (silindiğinden beri), birisi derleyicinin sabit ifadeleri derleme zamanında değerlendirebileceğine işaret etti. Hangisi doğru, ancak bu durumda alakalı değil, çünkü bağlamında

1/0 sabit bir ifade değildir .

Bir sabit ekspresyon azaltan bir sözdizimsel bir kategoridir koşullu ekspresyonu (ki hariç atamaları ve virgül ifadeler). Üretim sabiti ifadesi , dilbilgisinde yalnızca durum etiketleri gibi sabit bir ifade gerektiren bağlamlarda görünür . Yani yazarsan:

o zaman 1/0sabit bir ifadedir - ve 6.6p4'teki kısıtlamayı ihlal eden bir ifade: "Her bir sabit ifade, türü için gösterilebilir değerler aralığında olan bir sabit olarak değerlendirilmelidir.", bu nedenle bir teşhis gereklidir. Ancak bir atamanın sağ tarafı bir sabit ifade gerektirmez , yalnızca bir koşullu ifade gerektirir , bu nedenle sabit ifadeler üzerindeki kısıtlamalar uygulanmaz. Derleyici ama bağlamında, yürütme sırasında değerlendirilir (ya da sanki davranışı aynı olduğu takdirde, derleme zamanında yapabilen herhangi bir ifade değerlendirebilir if (0), değil, yürütme sırasında değerlendirilir ().

(Tam olarak benzer bir görünüm olduğu bir şey sabit ekspresyon mutlaka değil, sabit bir ifade içinde, gibi, x + y * zsekans x + ybir değil, katkı maddesi-sentezleme için göründüğü bağlam).

Bu, N1570 bölüm 6.6'daki alıntı yapacağım dipnot anlamına gelir:

Bu nedenle, aşağıdaki ilklendirmede
static int i = 2 || 1 / 0;
ifade, değeri bir olan geçerli bir tamsayı sabit ifadesidir.

aslında bu soruyla alakalı değil.

Son olarak, yürütme sırasında olanlarla ilgili olmayan tanımlanmamış davranışlara neden olmak için tanımlanan birkaç şey vardır. C standardının Ek J, bölüm 2'si (yine N1570 taslağına bakın ), standardın geri kalanından toplanan tanımlanmamış davranışa neden olan şeyleri listeler. Bazı örnekler (bunun kapsamlı bir liste olduğunu iddia etmiyorum):

  • Boş olmayan bir kaynak dosyası, hemen önünde ters eğik çizgi karakteri bulunmayan veya kısmi bir ön işleme belirteci veya yorumla biten yeni bir satır karakteriyle bitmez
  • Belirteç birleştirme, evrensel bir karakter adının sözdizimiyle eşleşen bir karakter dizisi üretir
  • Bir tanımlayıcı, bir karakter sabiti, bir dize değişmezi, bir başlık adı, bir açıklama veya hiçbir zaman bir jetona dönüştürülmeyen bir ön işleme belirteci dışında, bir kaynak dosyada temel kaynak karakter kümesinde olmayan bir karakterle karşılaşılır.
  • Bir tanımlayıcı, açıklama, dize değişmezi, karakter sabiti veya başlık adı geçersiz bir çok baytlı karakter içeriyor veya ilk vardiya durumunda başlamıyor ve bitmiyor
  • Aynı tanımlayıcı, aynı çeviri biriminde hem dahili hem de harici bağlantıya sahiptir

Bunlar belirli vakalar derleyici şeylerdir olabilir algılar. Komite tüm uygulamalara aynı davranışı empoze etmek istemedi ya da empoze edemediğinden davranışlarının tanımsız olduğunu düşünüyorum ve bir dizi izin verilen davranışı tanımlamak çabaya değmezdi. "Asla çalıştırılmayacak kod" kategorisine girmiyorlar, ama burada tamlık için onlardan bahsediyorum.


2
@EricPostpischil 6.6 / 4, "Her bir sabit ifade, türü için gösterilebilir değerler aralığında olan bir sabitle değerlendirilecektir" diyor. Bu 1/0, sabit bir ifade olmaktan çıkarılmaz mı?
Casey

2
@EricPostpischil: Bunun doğru olduğunu düşünmüyorum. Bir kısıtlamayı ihlal genellikle teşhis derleme zamanı, gerekli olduğu anlamına gelir değil, sadece başka türlü bir şey olabilir o foo bir değil foo . soru bağlamında1/0 sabit bir ifade değildir çünkü sabit bir ifade olarak ayrıştırılmaz , yalnızca bir atama ifadesinin parçası olan koşullu bir ifade olarak çözümlenir . kısıtlamayı ihlal eder ve bir teşhis gerektirir. case 1/0:
Keith Thompson

DR # 109, programın UB olmadığını gösteriyor gibi görünüyor, az önce gönderdiğim yeni cevaba bakın.
ouah

1
Yeniden " bu yüzden ortak İngilizce anlamına geri dönüyoruz ", İngilizce anlamında program, programda mevcutsa bir yapı kullanır. Öyleyse neden cevabınız bir yapı kullanmanın bir yapıyı yürütmek anlamına geldiğini varsayıyor? Senin sonucun açıklamandan gelmiyor!
ikegami

31

Bu makale bu soruyu Bölüm 2.6'da tartışmaktadır:

Yazarlar, programın sona ermediği zaman tanımlandığını düşünüyor guard(). Ayrıca kendilerini "statik olarak tanımlanmamış" ve "dinamik olarak tanımlanmamış" kavramlarını ayırt ederken bulurlar, örneğin:

Standart 11'in arkasındaki amaç , genel olarak durumların, onlar için kod üretilmesi kolay değilse, statik olarak tanımsız hale getirilmesidir. Yalnızca kod üretilebildiği zaman, durum dinamik olarak tanımlanamaz.

11) Komite üyesi ile özel yazışmalar.

Makalenin tamamına bakmanızı tavsiye ederim. Birlikte ele alındığında tutarlı bir resim çiziyor.

Makalenin yazarlarının soruyu bir komite üyesiyle tartışmak zorunda kalması, standardın şu anda sorunuzun cevabında belirsiz olduğunu doğrulamaktadır.


1
Bu örnek, yalnızca davranışının tanımsız olup olmadığını statik olarak belirleyip belirleyemeyeceğiniz konusunda zorluklar sunar . Çalıştırıldığında (davranışının guard()tanımsız olmadığı varsayılarak ), davranış, ancak ve ancak ifade 5 / 0;gerçekten yürütülüyorsa tanımsızdır . (Bir derleyicinin değerlendirmesini meşru 5 / 0olarak bir çağrı abort()veya benzer bir şeyle değiştirebileceğini unutmayın ; program bu durumda ancak ve ancak yürütme bu noktaya ulaşırsa iptal eder.) Bir derleyici, yalnızca bunun her zaman sona ereceğini belirleyebilirse bu programı reddedebilirguard() .
Keith Thompson

@KeithThompson Makaledeki statik / dinamik ayrımı açıklığa kavuşturmak için 5/0 dinamik olarak kabul edilir çünkü derleyici sıfıra bölen kod üretebilir: sadece z'yi 0'a ayarladıktan sonra z'ye bölen olağan kodu üretin. Böylece saf bir derleyici bir bölme talimatı oluşturabilir. Sonlanmayacağını belirleyen karmaşık bir derleyicinin guard()5/0 için herhangi bir kod üretmesi gerekmez. Bunun tersine, kod üretmenin bir yolu yoktur (int)(void)5, sadece kod üretilemez (int)(void)z, çünkü bu da doğru değildir. Yani yazarlar şunu düşünüyor ...
Pascal Cuoq

@KeithThompson… bir derleyicinin, if (0) (int)(void)5;naif derleyiciye sunduğu muamma nedeniyle programı reddetmesine izin verilir , oysa erişilemez dinamik UB if (0) 5 / 0;zararsızdır. Bir komite üyesiyle yaptıkları tartışmalardan ortaya çıkan buydu ve başka bir yerde benzer bir argümanın yapıldığını gördüm (ama belki de aynı kaynaktan, özellikle nerede olduğunu hatırlamadığım için). Şu anda C99 mantığını gözden geçiriyorum, bundan bahsettiğimi görürsem geri gelip işaret edeceğim.
Pascal Cuoq

2
(int)(void)5bir kısıtlama ihlalidir. N1570 6.5.4, cast operatörünü açıklamaktadır: "Kısıtlamalar: Tip adı bir boşluk tipi belirtmedikçe, tip adı atomik, nitelikli veya niteliksiz skaler tipi belirtecek ve işlenen skaler tipe sahip olacaktır." (void)5skaler türe sahip değildir, bu nedenle (int)(void)5onu içeren kodun çalıştırılıp çalıştırılmadığına bakılmaksızın bu kısıtlamayı ihlal eder.
Keith Thompson

@KeithThompson Evet, yanlış örneği seçmiş gibi görünüyorlar, ancak J.2'deki uzun listede, kısıt ihlali olmayan bir tane var ve bu kesinlikle "statik"? Şu eski klasik, "Boş olmayan bir kaynak dosyası yeni satır karakteriyle bitmez…" nasıl olur? Bunun için geçerli olan erişilebilirlik kavramı yok, ama bu bir kısıtlama ihlali değil, değil mi?
Pascal Cuoq

5

Bu durumda tanımsız davranış, kodun çalıştırılmasının sonucudur. Yani kod çalıştırılmazsa, tanımlanmamış bir davranış yoktur.

Tanımlanmamış davranış, yalnızca kodun bildirilmesinin sonucuysa (örneğin, bazı değişken gölgelendirme durumları tanımsız ise), yürütülmeyen kod tanımlanmamış davranışı çağırabilir.


Örnek 2'nin bir örneği için #include "//e"hangisinin UB'yi çağırdığını düşünün .
Michael Foukarakis

2

Bu cevabın son paragrafıyla giderdim: https://stackoverflow.com/a/18384176/694576

... UB bir çalışma zamanı sorunu, derleme zamanı sorunu değil ...

Yani hayır, çağrılan UB yok.


2
İnternette okuduğunuz her şeye inanmamalısınız, özellikle de StackOverflow cevabından değil.
Pascal Cuoq

1
@PascalCuoq Bu, benim gibi birçok SO'ya inananların inancını paramparça ediyor. Şimdi nereye gitmeli?
0decimal 0

2

Sadece standart son derece önemli değişiklikler yaptığında ve kodunuz aniden "asla çalıştırılmadığında". Ancak bunun 'tanımsız davranışa' neden olabileceği herhangi bir mantıksal yol görmüyorum. Hiçbir şeye neden olmuyor .


2

Tanımlanmamış davranış konusunda resmi yönleri pratik olanlardan ayırmak genellikle zordur. Bu, 1989 standardındaki tanımlanmamış davranışın tanımıdır (elimde daha yeni bir sürüm yok, ancak bunun büyük ölçüde değişmesini beklemiyorum):

1 tanımsız davranış
  taşınabilir olmayan veya hatalı bir program yapısının kullanılması veya
  Bu Uluslararası Standardın herhangi bir gereklilik getirmediği hatalı veriler
2 NOT Olası tanımlanmamış davranış, durumu tamamen görmezden gelmekten değişir
  öngörülemeyen sonuçlarla, çeviri veya program yürütme sırasında davranmak
  dokümante edilmiş bir şekilde çevrenin karakteristiği (ile veya olmadan)
  bir tanılama mesajının verilmesi), bir çeviriyi sonlandırmak veya
  yürütme (bir teşhis mesajının verilmesi ile).

Resmi bir bakış açısına göre, programınızın tanımsız davranışı çağırdığını söyleyebilirim, bu da standardın çalıştırıldığında ne yapacağına hiçbir koşul koymadığı anlamına gelir, çünkü sıfıra bölme içerir.

Öte yandan, pratik bir bakış açısıyla, sezgisel olarak beklediğiniz gibi davranmayan bir derleyici bulduğumda şaşırırdım.


2

Standart, doğru hatırladığım gibi, o andan itibaren her şeyi yapmasına izin verildiğini, bir kuralın ihlal edildiğini söylüyor. Belki küresel bir tada sahip bazı özel olaylar vardır (ama böyle bir şeyi hiç duymadım veya okumadım) ... Yani şunu söyleyebilirim: Hayır bu UB olamaz, çünkü davranış iyi tanımlandığı sürece 0 her zaman false, bu nedenle kural çalışma zamanında ihlal edilemez.


0 her zaman doğru mu? ya da her zaman doğru mu? bir çeşit yakutçu musun ?!
Grady Oyuncu

@Grady PlayerNo Ben bir çeşit Brain afkıydım. Düzelteceğim, üzgünüm
13:17

2

Bunun hala tanımlanmamış bir davranış olduğunu düşünüyorum, ancak standartta beni destekleyecek veya reddedecek herhangi bir kanıt bulamıyorum.

Programın tanımsız davranışa yol açmadığını düşünüyorum.

Kusur Raporu # 109 benzer bir soruyu ele alıyor ve şöyle diyor:

Ayrıca, belirli bir programın olası her yürütülmesi tanımsız davranışla sonuçlanıyorsa, verilen program tam olarak uyumlu değildir. Uygun bir uygulama, tam olarak uyumlu bir programı çevirmekte başarısız olmamalıdır, çünkü o programın olası bir şekilde yürütülmesi tanımlanmamış davranışa neden olabilir. Foo hiçbir zaman çağrılamayabileceğinden, verilen örnek uygun bir uygulama ile başarıyla çevrilmelidir.


-1

"Tanımlanmamış davranış" ifadesinin nasıl tanımlandığına ve bir ifadenin "tanımsız davranışının" bir program için "tanımlanmamış davranış" ile aynı olup olmadığına bağlıdır.

Bu program C'ye benziyor, bu nedenle derleyici tarafından kullanılan C standardının (bazı cevapların yaptığı gibi) daha derin bir analizi uygundur.

Belirli bir standardın yokluğunda, doğru cevap "duruma göre değişir" dir. Bazı dillerde, derleyicilerin tahminine göre, ilk hatadan sonra derleyiciler programcının ne anlama geldiğini tahmin etmeye çalışır ve yine de bazı kodlar üretir. Diğer, daha saf dillerde, bir şey tanımlanmadığında, tanımsızlık tüm programa yayılır.

Diğer dillerde "sınırlı hatalar" kavramı vardır. Bazı sınırlı hata türleri için, bu diller bir hatanın ne kadar zarar verebileceğini tanımlar. Özellikle, ima edilen çöp toplama özelliğine sahip diller, bir hatanın yazım sistemini geçersiz kılıp kılmaması konusunda sıklıkla fark yaratır.

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.