C ++ 'da işaretli tamsayı taşması hala tanımsız bir davranış mı?


84

Bildiğimiz gibi, işaretli tamsayı taşması tanımsız bir davranıştır . Ancak C ++ 11 cstdintbelgelerinde ilginç bir şey var :

tam olarak 8, 16, 32 ve 64 bit genişliğinde, doldurma bitleri olmadan ve negatif değerler için 2'nin tümleyicisini kullanan işaretli tamsayı türü (yalnızca uygulama doğrudan türü destekliyorsa sağlanır)

Bağlantıya bakın

Ve işte sorum şu: standart açıkça şunu söylüyor: int8_t , int16_t, int32_tve int64_tnegatif sayılar 2 tümleyen konusunda, hala taşma bu tür tanımlanmamış bir davranış mı?

Düzenle C ++ 11 ve C11 Standartlarını kontrol ettim ve işte bulduğum şey:

C ++ 11, §18.4.1:

Başlık, tüm fonksiyonları, türleri ve makroları C standardındaki 7.20 ile aynı şekilde tanımlar.

C11, §7.20.1.1:

Typedef adı intN_t, N genişliğinde, dolgu biti içermeyen ve ikinin tamamlayıcı gösterimi olan işaretli bir tamsayı türünü belirtir. Bu nedenle, int8_ttam olarak 8 bit genişliğinde böyle bir işaretli tamsayı türünü belirtir.


14
C ++ için tek birincil belgenin standart olduğunu asla unutmayın . Diğer her şey, hatta CppReference gibi bir wiki bile ikincil bir kaynaktır. Bu yanlış olduğu anlamına gelmez; sadece tamamen güvenilir değil.
Nicol Bolas

UB olmasını beklerdim, C de bu tipler için bir muafiyet yok, C ++ neden bir tane ekleyecekti anlamıyorum.
Daniel Fischer


3
Biraz kafam karıştı: "Tamamen 8, 16, 32 ve 64 bit genişliğinde, doldurma biti olmayan ve negatif değerler için 2'nin tamamlayıcısı kullanan" işaretli tamsayı türü "cümlesindeki fiil nerede (yalnızca uygulama doğrudan destekliyorsa sağlanır) türü)? " Biraz eksik mi? Bunun anlamı ne?
YSC

C ++ 11, C11'e değil, C99'a dayanır. Ama bu zaten önemli değil
LF

Yanıtlar:


81

hala bu türlerin aşılması tanımlanmamış bir davranış mı?

Evet. C ++ 11 Standardının 5/4 Paragrafına göre (genel olarak herhangi bir ifade ile ilgili olarak):

Bir ifadenin değerlendirilmesi sırasında, sonuç matematiksel olarak tanımlanmamışsa veya türü için gösterilebilir değerler aralığında değilse , davranış tanımsızdır . [...]

Bir ikinin tümleyen temsilinin bu işaretli türler için kullanılması, bu türlerin ifadelerini değerlendirirken aritmetik modulo 2 ^ n'nin kullanıldığı anlamına gelmez.

İlgili imzasız aritmetik, diğer taraftan, Standart açıkça ki (Paragraf 3.9.1 / 4) belirtir:

Tamsayılar, ilan unsigned, aritmetik modülo uyun eder 2 ^ n burada, n, bir tamsayı, belirli büyüklükte bir değer temsil bit sayısıdır

Bu, işaretsiz aritmetik işlemin sonucunun her zaman " matematiksel olarak tanımlandığı " ve sonucun her zaman gösterilebilir aralıkta olduğu anlamına gelir; bu nedenle 5/4 geçerli değildir. Dipnot 46 bunu açıklar:

46) Bu, işaretsiz aritmetiğin taşmaması anlamına gelir, çünkü sonuçta ortaya çıkan işaretsiz tamsayı türü ile temsil edilemeyen bir sonuç, sonuçta ortaya çıkan işaretsiz tamsayı türü tarafından temsil edilebilen en büyük değerden bir büyük olan sayı modulo azaltılır.


1
Bu paragraf aynı zamanda işaretsiz taşmanın tanımsız olduğunu, ki bunun olmadığını ima eder.
Archie

8
@Archie: Pek değil, imzasız değerler tanımlı olduğu modülo imzasız aralık.
Orbit'te Hafiflik Yarışları

3
@Archie: Açıklığa kavuşturmaya çalıştım ama temelde cevabı LightnessRacesinOrbit'ten aldınız
Andy Prowl

1
İmzasız taşmanın tanımlanıp tanımlanmaması önemli değil, modulo hesaplaması nedeniyle gerçekleşemiyor ...
Aconcagua

1
Sonucu "matematiksel olarak tanımlanmayan" işaretsiz işlemler vardır - özellikle sıfıra bölme - bu yüzden belki de ifadeniz bu cümlede tam olarak kastettiğiniz şey değildir. ITYM , sonuç matematiksel olarak tanımlandığında , C ++ 'da da tanımlanır.
Toby Speight

22

Bir tür sadece tamamlayıcı gösterimini kullanacak şekilde tanımlandığı için, bu türdeki aritmetik taşmanın tanımlı hale gelmesi sonucu çıkmaz.

İşaretli aritmetik taşmanın tanımsız davranışı, optimizasyonları etkinleştirmek için kullanılır; örneğin, derleyici, eğer a > böyleyse a + 1 > b; bu, a + 1etrafına sarılabilecek olasılık nedeniyle ikinci kontrolün yapılması gereken işaretsiz aritmetikte geçerli değildir 0. Ayrıca, bazı platformlar aritmetik taşmada bir tuzak sinyali oluşturabilir (bkz. Örneğin http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html ); standart bunun olmasına izin vermeye devam ediyor.


5
Birçok kişinin tuzakların olasılıkları hakkında daha fazla "endişelendiğini" belirtmekte fayda var, ancak derleyici varsayımları aslında daha sinsi (keşke nedenlerinden biri, Uygulama Tanımlı ve Tanımsız Davranış arasında bir kategori olsaydı - uygulama tanımlı davranıştan farklı olarak) Bu, tutarlı bir şekilde belgelenmiş bir şekilde bir şeyler yapmak için belirli uygulamaları gerektiren, uygulamaların bir şeyin sonucu olarak olabilecek her şeyi belirtmesini gerektiren "uygulama ile sınırlı" bir davranış istiyorum (özellikler açıkça Tanımsız Davranış içerebilir, ancak .. .
supercat

3
... uygulamaların pratik olduğunda daha spesifik olması teşvik edilecektir). İki tamamlayıcı sayının doğal olarak "kaydırılacağı" bir donanımda, tamsayı taşması olmadan gerçekleştirmeye çalışan birçok talimatı yürütmek için sarmalanmış bir tamsayı sonucu isteyen kod için mantıklı bir neden yoktur, bu donanımın yalnızca bir veya iki talimatla yapabileceği bir hesaplama .
supercat

1
@supercat Aslında, sarılmış sonuç isteyen kod (2'nin tamamlayıcı CPU'larında) sadece işlenenleri karşılık gelen işaretsiz türlere çevirebilir ve işlemi gerçekleştirebilir (ve sonra geri dönüş yaparak uygulama tanımlı değeri elde edebilir): bu, toplama, çıkarma ve çarpma için çalışır . Tek sorun, bölme, modulo ve abs. Çalışırken bu işlemler için, işaretli aritmetikten daha fazla talimat gerektirmez.
Ruslan

@Ruslan: Kodun tam olarak sarılmış bir sonuca ihtiyaç duyduğu durumlarda, işaretsizlere çevirme çirkin olur, ancak mutlaka ekstra kod üretmez. Daha büyük bir sorun, zamanının çoğunu ilgi çekici olmayan adayları reddetmekle geçirecek olan "potansiyel olarak ilginç" adayları hızlı bir şekilde tanımlaması gereken kodla ilgili olabilir. Bir derleyiciye, işaretli tamsayı değerleriyle ekstra kesinliği keyfi olarak tutma veya atma özgürlüğü verirse, ancak bir tamsayı türüne geri dönüşün böyle bir kesinliği kesmesini gerektiriyorsa, bu, taşma UB yaparak elde edilebilecek yararlı optimizasyonların çoğunu mümkün kılacaktır. , ...
supercat

... ancak hassas sarma gerektiren kodun iki yerine bir dönüşüm kullanmasına izin verir (ör. (int)(x+y)>zsarılmış bir sonucu karşılaştırır) ve ayrıca programcıların x+y>zkodun 0 veya 1 vermesinin kabul edilebilir olduğu durumlarda yazmasına izin verir başka bir yan etkisi olmaması koşuluyla taşma oranı . 0 ya da 1 ya da ya göre bu oldukça programcı yazma izin eşit derecede kabul edilebilir bir sonuç olurdu (long)x+y>zveya (int)((unsigned)x+y)>zderleyici seçmek için olanak sağlayacak ikinci fonksiyon hangisi [Her bazı durumlarda ucuz olması] herhangi bir bağlamda ucuz.
supercat

1

Eminim öyledir.

Standart belgelerden (sayfa 4 ve 5):

1.3.24 tanımlanmamış davranış

Bu standardın herhangi bir gereklilik getirmediği davranış

[Not: Bu Uluslararası Standart herhangi bir açık davranış tanımını atladığında veya bir program hatalı bir yapı veya hatalı veri kullandığında, tanımlanmamış davranış beklenebilir. İzin verilebilir tanımsız davranış, durumu tamamen öngörülemeyen sonuçlarla göz ardı etmekten, çeviri veya program yürütme sırasında çevrenin özelliği olan belgelenmiş bir şekilde davranmaya (bir teşhis mesajı vererek veya yayınlamadan), bir çeviriyi veya yürütmeyi sonlandırmaya (yayınlama ile) bir teşhis mesajı). Birçok hatalı program yapısı tanımlanmamış davranışlara yol açmaz; teşhis edilmeleri gerekir. - son not]

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.