Soru (1) iken; C de tanımlanmamış davranış?


İçinde C ++ 11 Tanımsız Davranışıdırama bu durumda C while(1); Tanımsız Davranışı Nedir?


19
2018-05-08 08:44


Menşei


Sanırım for(;;)  C ifadesi iyi tanımlanmış sonra while(1) C olarak tanımlanmamalı ... sonsuz döngü algılamayı hatırlamıyor. - Grijesh Chauhan
Eğer isterseniz 6.8.5 reklam 6 üzerinde biraz daha ayrıntılı çalışabilirim ve özellikle de derleyici firmanın bu maddeden faydalanmasının neden pek muhtemel olmadığına inanıyorum. - Bryan Olivier
@BryanOlivier bunun için gitmek :) - Tony The Lion
@Tony, teşekkürler, bir hobi atına binmek her zaman güzeldir. - Bryan Olivier


Cevaplar:


İyi tanımlanmış bir davranış. C11’de yeni bir madde 6.8.5 reklam 6 eklendi

Kontrol ifadesi sürekli bir ifadesi olmayan bir yineleme ifadesi,156) hiçbir girdi / çıktı işlemi gerçekleştirmez, uçucu nesnelere erişemez ve vücudunda hiçbir senkronizasyon veya atomik işlem gerçekleştirmez, ifadeyi kontrol edebilir veya (for ifadesinde) ifadesi-3, uygulama tarafından üstlenilebilir. sonlandırabilir.157)


157)Bu, sonlandırma kanıtlanamadığında bile boş döngülerin kaldırılması gibi derleyici dönüşümlerine izin vermeyi amaçlamaktadır.

Döngünün kontrol ifadesi sabit olduğundan, derleyici döngü sona erdiğini varsaymayabilir. Bu, bir işletim sistemi gibi sonsuza kadar çalışması gereken reaktif programlar için tasarlanmıştır.

Ancak, aşağıdaki döngü için davranış belirsizdir

a = 1; while(a);

Aslında bir derleyici bu döngüyü kaldırabilir veya kaldırmayabilir, bu da sonlandırabilecek veya sonlanmayabilecek bir program ile sonuçlanır. Bu, sabit diskinizi silmenize izin verilmediğinden, gerçekten tanımlanmamış değildir, ancak kaçınılması gereken bir yapımdır.

Ancak başka bir sapma var, aşağıdaki kodu dikkate alın:

a = 1; while(a) while(1);

Derleyicinin dış döngü sona erdiğini düşünebileceğinden, iç döngü de sonlandırılmalı, dış halka nasıl sonlanabilecektir. Yani gerçekten akıllı bir derleyiciniz varsa o zaman while(1); Sonlandırılmaması gereken döngü, etrafına bu şekilde sonlanmayan döngülere sahip olmalıdır. main. Eğer sonsuz döngüyü gerçekten istiyorsan, biraz daha okumalısın ya da yazarsın volatile değişkeni.

Bu madde neden pratik değil?

Derleyici firmamızın bu cümleden faydalanacağı pek de ihtimal dışıdır çünkü esasen çok sözdizimsel bir özelliktir. Ara gösterimde (IR), yukarıdaki örneklerde sabit ve değişken arasındaki fark, sürekli yayılma yoluyla kolayca kaybolur.

Maddenin amacı, derleyici yazarlarının aşağıdaki gibi istenen dönüştürmeleri uygulamalarına izin vermektir. Çok nadir olmayan bir döngü düşünün:

int f(unsigned int n, int *a)
{       unsigned int i;
        int s;

        s = 0;
        for (i = 10U; i <= n; i++)
        {
                s += a[i];
        }
        return s;
}

Mimari nedenlerden dolayı (örneğin donanım döngüleri) bu kodu şu şekilde değiştirmek istiyoruz:

int f(unsigned int n, int *a)
{       unsigned int i;
        int s;

        s = 0;
        for (i = 0; i < n-9; i++)
        {
                s += a[i+10];
        }
        return s;
}

Madde 6.8.5 reklam 6 olmadan, bu mümkün değildir, çünkü eğer n eşittir UINT_MAX, döngü sonlanmayabilir. Yine de, bir insan için bu, bu kodun yazarının amacı değil, oldukça açıktır. Madde 6.8.5 reklam 6 şimdi bu dönüşüme izin veriyor. Ancak, bunun başarılma şekli, bir sonsuz yazıcının sözdizimsel gereksiniminin IR üzerinde sürdürülmesi zor olduğundan, bir derleyici yazarı için çok pratik değildir.

Önemli olduğunu unutmayın n ve i Hangi unsigned taşma olarak signed int tanımlanmamış davranışlar verir ve bu nedenle dönüşüm bu nedenle haklı çıkarılabilir. Verimli kod, ancak kullanmanın yararları unsignedDaha büyük pozitif aralığın dışında.

Alternatif bir yaklaşım

Yaklaşımımız, kod yazanın niyetini, örneğin assert(n < UINT_MAX) döngüden önce veya bazı Frama-C benzeri garantiler. Bu şekilde derleyici, "sonlandırma" işlemini "kanıtlayabilir" ve 6.8.5 numaralı reklam 6'ya dayanmak zorunda kalmaz.

P.S: Ben 12 Nisan 2011 tarihinde bir taslak bakıyorum paxdiablo açıkça farklı bir versiyona bakıyor, belki onun versiyonu daha yeni. Alıntıda sürekli ifade unsuru belirtilmez.


22
2018-05-08 08:57



Ben de n1570'e bakıyorum, ve paxdiablo'nun teklifinin orada olduğunu garanti ediyorum, sayfanın sonunda 150 (Adobe Reader sayfa numaralarında 168) ... - autistic
@undefinedbehaviour N1570'i yeni indirdim ve hala, "kontrol ifadesi sabit bir ifade değil" için bir istisnanın yapıldığı yan tümcelerimde bulunan bir sürüm var. Ama yukarıda tartıştığım gibi, gerçekten yardımcı olmuyor. - Bryan Olivier
Ah. Bu ilacı fark etmemiştim. Çok iyi. Baktığın kişi en güncel C11 standart taslağı. - autistic
+1 çok güzel cevap - Shafik Yaghmour
Derleyici, yayılmış bir sabitin başka nedenlerden dolayı sürekli bir ifade olup olmadığını takip etmek zorunda kalmıştır. Örneğin, sizeof(*(char (*)[1])a++) artmaz a, fakat sizeof(*(char (*)[non_constexpr_1])a++) yapar. - R..


Giriş yaptıktan sonra taslak C99 standardı, "Hayır" derdim, tanımsız değil. Taslakta, iterasyonların sona ermesi gerektiğini belirten bir dil bulamıyorum.

Yinelenen ifadelerin anlamlarını açıklayan paragrafın tam metni:

Yineleme ifadesi, döngü gövdesi olarak adlandırılan bir ifadeye neden olur   Kontrol ifadesi 0'a eşit olana kadar tekrar tekrar yürütülür.

Varsa, C ++ 11 için belirlenmiş olan herhangi bir sınırlama var. Ayrıca, herhangi bir kısıtlamadan bahsetmeyen "Kısıtlamalar" adlı bir bölüm de vardır.

Elbette, şüphesiz ben gerçek standart başka bir şey söyleyebilir.


5
2018-05-08 08:51





En basit cevap, uygun bir uygulamanın minimum gerekliliklerini belirten §5.1.2.3p6'dan bir alıntı içerir:

Uygun bir uygulamadaki en düşük gereksinimler şunlardır:

- Uçucu nesneler için erişim kesinlikle göre değerlendirilir   soyut makinenin kuralları.

- Program sonlandırılmasında, dosyalara yazılan tüm veriler   Sonuç olarak, programın   soyut semantik üretebilirdi.

- Etkileşimli cihazların giriş ve çıkış dinamikleri   7.21.3'te belirtildiği gibi yerleştirin. Bu şartların amacı,   arabelleğe alınmamış veya satır tamponlu çıktı mümkün olan en kısa sürede   İletilerin istenmesinin bir programdan önce gerçekten göründüğünden emin olun   girişi bekliyorum.

Bu, programın gözlemlenebilir davranışıdır.

Makine kodu, gerçekleştirilen optimizasyonlar nedeniyle gözlemlenebilir davranışı üretemezse, derleyici bir C derleyicisi değildir. Fesih noktasında sadece böyle sonsuz bir döngü içeren bir programın gözlemlenebilir davranışı nedir? Böyle bir döngünün bitmesinin tek yolu, erken bir zamanda bitmesine neden olan bir sinyaldir. Bu durumuda SIGTERM, program sona erer. Bu gözlemlenebilir bir davranışa neden olmaz. Bu nedenle, o programın tek geçerli optimizasyonu derleyicinin programı kapatarak sistemi derhal durdurması ve hemen biten bir program oluşturmasıdır.

/* unoptimised version */
int main() {
    for (;;);
    puts("The loop has ended");
}

/* optimised version */
int main() { }

Bir olasılık, bir sinyalin kaldırılması ve longjmp'in, infazın farklı bir yere atlanması için çağrılmasıdır. Atlanabilecek tek yer, döngüden önce yürütme sırasında ulaşılan bir yer gibi gözüküyor, bu yüzden derleyicinin sağlanması, bir sinyalin başka bir yere atlanmasına neden olan bir sinyalin yükseltildiğini fark edecek kadar akıllı, potansiyel olarak döngüleri optimize edebilir (ve sinyal yükselterek) hemen atlamadan yanadır.

Birden çok iş parçacığı denkleme girdiğinde, geçerli bir uygulama, programın sahipliğini ana iş parçacığından farklı bir iş parçacığına aktarabilir ve ana iş parçacığını sonlandırabilir. Programın gözlemlenebilir davranışı, optimizasyondan bağımsız olarak hala gözlemlenebilir olmalıdır.


1
2018-05-08 10:32



Adın neredeyse bu soru için bir yenilik hesabı gibidir. - Tony The Lion


Aşağıdaki ifade C11 6.8.5 Iteration statements /6:

Kontrol ifadesi sabit bir ifade olmayan, hiçbir giriş / çıkış işlemi gerçekleştirmeyen bir uçbirim ifadesi uçucuya erişemez.   nesneleri, ve, kendi deyiminde hiçbir ifadeyi veya atom işlemlerini gerçekleştirmez, ifadeyi denetler veya (ifadesi için) ifadesinin (3) ifadesi, uygulamanın sona erdirilmesiyle kabul edilebilir.

Dan beri while(1);  kullanımları Sabit bir ifade, uygulamanın sonlandıracağını varsaymasına izin verilmez.

Bir derleyici olduğu Böyle bir döngüyü tamamen kaldırmakta serbesttir, ifade sabit değildir ve tüm diğer koşullar benzer şekilde yerine getirilir, sonuçta döngünün sona ereceği kesin olarak kanıtlanamaz.


1
2018-05-08 08:57



Tam olarak değil onu sonlandırmak için ücretsiz. Programın gözlemlenebilir davranışının karşılanmasını sağlamak için daha fazla işlem yapılması gerekecektir. Döngü takip eden bir kod yoksa, derleyicinin bunu da optimize etmesi gerekir. - autistic
@undefinedbehaviour Ben farklı olmak için yalvarıyorum. Döngüden sonra gözlemlenebilir herhangi bir davranışın, bir değişkenle döngüden dolayı ulaşılamayabilir gibi görünebileceğini düşünüyorum, bu maddenin ifadesiyle ulaşılabilir ve yapılabilir. değil En iyi duruma getirilmelidir (ilk). - Bryan Olivier
@ R.I.P.Seb: Standardın bir derleyicinin neye izin verildiğini belirtmesini isterdim yapbir varsayım temelinde. IMHO, bir öntanımlı olarak mantıklı olabilir: "imzasız uzun uzun test (imzasız uzun uzun a)" {a = dışAşama ile (a);) iken (a! = 1); printf ("Sona erdi!" printf ("Sonuç =% lld", a); return a;} "ilk printf ile paralel olarak yürütülen" while "gibi davranmasına izin verilir, ancak ikinci printf [ve işlevden dönüş] "a" aslında bir tane değeri atanana kadar beklemek zorunda kalacaktı. Fonksiyonun amacı ... - supercat
... bir fonksiyonun sonunda geri döneceğini, bir optimizatörün “olması” gerektiğine karar verdiğini ve bu yüzden yardımcı olmadığını teyit etmektir. - supercat
@BryanOlivier Yazdığım gibi, "Programın gözlemlenebilir davranışının karşılanmasını sağlamak için daha fazla işlem yapılması gerekiyor." Nedenini söyler misin bu program bir şey basmıyor mu? - autistic