En iyi cevap yanlış (ancak yaygın) bir yanlış anlamadır:
Tanımsız davranış, bir çalışma zamanı özelliğidir *. Bu DEĞİL CAN "zaman yolculuğu"!
Bazı operasyonlar (standart olarak) yan etkilere sahip olacak şekilde tanımlanır ve optimize edilemez. G / Ç yapan veya volatile
değişkenlere erişen işlemler bu kategoriye girer.
Ancak , bir uyarı var: UB, önceki işlemleri geri alan davranış da dahil olmak üzere herhangi bir davranış olabilir . Bu, bazı durumlarda, önceki kodu optimize etmeye benzer sonuçlar doğurabilir.
Aslında, bu en üstteki cevapla tutarlıdır (vurgu benim):
İyi biçimlendirilmiş bir programı yürüten uygun bir uygulama, aynı program ve aynı girdiyle soyut makinenin karşılık gelen örneğinin olası yürütmelerinden biri ile aynı gözlemlenebilir davranışı üretecektir.
Bununla birlikte, bu tür bir yürütme tanımlanmamış bir işlem içeriyorsa, bu Uluslararası Standart, bu programı bu girdi ile yürüten uygulamaya herhangi bir gereklilik getirmez (ilk tanımsız işlemden önceki işlemlerle ilgili olarak bile).
Evet, bu alıntı yapar demek "bile ilk tanımsız operasyonundan önceki operasyonlar kapsamında" bu özellikle ediliyor yaklaşık kod olduğunu, ancak haber yürütülen , sadece derlenmiş değil.
Sonuçta, gerçekte ulaşılmayan tanımsız davranış hiçbir şey yapmaz ve UB içeren satıra gerçekten ulaşılması için, ondan önce gelen kod önce yürütülmelidir!
Yani evet, UB yürütüldüğünde , önceki işlemlerin herhangi bir etkisi tanımsız hale gelir. Ancak bu gerçekleşene kadar, programın yürütülmesi iyi tanımlanmıştır.
Bununla birlikte, programın bunun gerçekleşmesine neden olan tüm yürütmelerinin, önceki işlemleri gerçekleştiren ancak daha sonra etkilerini kaldıranlar da dahil olmak üzere eşdeğer programlara optimize edilebileceğini unutmayın . Sonuç olarak, önceki kod, etkilerinin geri alınmasına eşdeğer olduğu her durumda optimize edilebilir ; aksi takdirde olamaz. Örnek için aşağıya bakın.
* Not: Bu, derleme zamanında meydana gelen UB ile tutarsız değildir . Derleyici aslında UB kodu kanıtlayabilirsek olacak her zaman tüm girişler için yürütülecek, daha sonra UB derleme zaman uzatabilirsiniz. Bununla birlikte, bu, önceki tüm kodun sonunda geri döneceğini bilmeyi gerektirir , bu da güçlü bir gerekliliktir. Yine, bir örnek / açıklama için aşağıya bakın.
Bunu somut hale getirmek için, aşağıdaki kodun onu izleyen tanımsız davranışlardan bağımsız olarak yazdırıp girdinizi beklemesi gerektiğini unutmayın foo
:
printf("foo")
getchar()
*(char*)1 = 1
Bununla birlikte, foo
UB oluştuktan sonra ekranda kalacağına veya yazdığınız karakterin artık giriş arabelleğinde olmayacağına dair bir garanti olmadığını da unutmayın ; bu işlemlerin her ikisi de "geri alınabilir", bu da UB "zaman yolculuğuna" benzer bir etkiye sahiptir.
Eğer getchar()
çizgi yoktu, o olur hatları uzakta optimize edilmesi için yasal yalnızca ve eğer olurdu farksız çıkışının foo
ardından ve onu "un-yapıyor".
İkisinin ayırt edilemez olup olmayacağı tamamen uygulamaya bağlıdır (yani derleyicinize ve standart kitaplığınıza). Örneğin, başka bir programın çıktıyı okumasını beklerken iş parçacığınızı burada printf
bloke edebilir mi? Yoksa hemen geri mi dönecek?
Burada engelleyebiliyorsa, başka bir program tam çıktısını okumayı reddedebilir ve asla geri dönmeyebilir ve sonuç olarak UB asla gerçekleşmeyebilir.
Hemen buraya dönebilirse, o zaman geri dönmesi gerektiğini biliyoruz ve bu nedenle onu optimize etmek, onu çalıştırmaktan ve sonra etkilerini yapmaktan tamamen ayırt edilemez.
Elbette, derleyici kendi özel sürümü için hangi davranışa izin verildiğini bildiğinden printf
, buna göre optimize edebilir ve sonuç printf
olarak bazı durumlarda optimize edilirken bazılarında optimize edilemez. Ancak, yine, gerekçe, bunun UB'nin önceki işlemlerini yapmamasından ayırt edilemez olması, önceki kodun UB nedeniyle "zehirlenmiş" olması değil.
a
(kendini hesaplamak dışında) ve kaldırına