(-2147483648> 0) C ++ 'da true değerini döndürür?


241

-2147483648, 32 bitli tamsayı türü için en küçük tamsayıdır, ancak if(...)cümlede taşacak gibi görünüyor :

if (-2147483648 > 0)
    std::cout << "true";
else
    std::cout << "false";

Bu truebenim testimde yazdırılacak . Ancak, -2147483648 değerini tamsayıya kullanırsak sonuç farklı olur:

if (int(-2147483648) > 0)
    std::cout << "true";
else
    std::cout << "false";

Bu yazdırılacaktır false.

Kafam karıştı. Herkes bu konuda bir açıklama yapabilir mi?


Güncelleme 02-05-2012:

Yorumlarınız için teşekkürler, derleyicimde int boyutu 4 bayt. Bazı basit testler için VC kullanıyorum. Sorumdaki açıklamayı değiştirdim.

Bu yazıda çok iyi cevaplar var, AndreyT , derleyicinin bu girdi üzerinde nasıl davranacağı ve bu minimum tamsayının nasıl uygulandığı hakkında çok ayrıntılı bir açıklama yaptı. Öte yandan qPCR4vir , ilgili bazı "merakları" ve tamsayının nasıl temsil edildiğini verdi. Çok etkileyici!


48
"Hepimiz biliyoruz ki -2147483648 tamsayı sayısının en azıdır" Bu tamsayı boyutuna bağlıdır.
orlp

14
"Hepimiz biliyoruz ki -2147483648 en az tamsayı sayısıdır" - En ufak bir tamsayı olmadığını düşündüm, çünkü sonsuz sayıda birçoğu var ... Her neyse.

@Inisheer ile 4 Bayt tamsayı Eğer bir olabilir INT_MINait -9223372036854775808ise, CHAR_BIT16. Ve hatta ile CHAR_BIT == 8ve sizeof(int== 4) `sen alabilirsiniz -9223372036854775807C2-Tamamlayıcı numaraları gerekmez çünkü.
12431234123412341234123

Yanıtlar:


391

-2147483648bir "sayı" değil. C ++ dili negatif değişmez değerleri desteklemez.

-2147483648aslında bir ifadedir: önünde 2147483648tekli -işleç olan pozitif bir değişmez değer . Değer 2147483648görünüşte olumlu tarafı için çok büyük intsenin platformda aralığında. Tipi ise long intplatformunuzda daha geniş kapsama alanı vardı, derleyici otomatik olarak varsaymak gerekir 2147483648sahiptir long inttürü. (C ++ 11'de derleyicinin long long inttürü de dikkate alması gerekir .) Bu, derleyiciyi -2147483648daha büyük türde etki alanında değerlendirir ve sonuç beklendiği gibi negatif olur.

Ancak, görünüşe göre sizin durumunuz aralığı aralığıyla long intaynıdır intve genel olarak intplatformunuzdakinden daha büyük bir tam sayı türü yoktur . Bu, pozitif sabitin 2147483648mevcut tüm imzalı tamsayı türlerini aştığı anlamına gelir, bu da programınızın davranışının tanımsız olduğu anlamına gelir. (Dil belirtiminin, bu gibi durumlarda, bir tanılama mesajı yerine tanımsız davranışları tercih etmesi biraz gariptir, ancak bu şekilde.)

Uygulamada, davranışın tanımsız olduğu dikkate alındığında, 2147483648uygulamaya -uygulandıktan sonra olumluya dönüşen uygulamaya bağlı bazı negatif değerler olarak yorumlanabilir . Alternatif olarak, bazı uygulamalar değeri göstermek için imzasız türler kullanmaya çalışabilir (örneğin, C89 / 90 derleyicilerinde kullanılması gerekiyordu unsigned long int, ancak C99 veya C ++ ile değil). Davranış zaten tanımsız olduğundan uygulamaların her şeyi yapmasına izin verilir.

Bir yan not olarak, bu gibi sabitlerin INT_MINtipik olarak

#define INT_MIN (-2147483647 - 1)

görünüşte daha basit yerine

#define INT_MIN -2147483648

İkincisi amaçlandığı gibi çalışmaz.


78
Bu yapıldığında nedeni de budur: #define INT_MIN (-2147483647 - 1).
orlp

5
@ RichardJ.RossIII - clang ile büyük olasılıkla 64 bitlik bir değişmezi alıyorsunuz, çünkü bir sığmayacak kadar büyüktü int. OP uygulamasının 64 bit türü olmayabilir.
Carl Norum

1
@ RichardJ.RossIII: Bu davranışın uygulama tanımlı / tanımsız olduğuna inanıyorum.
Oliver Charlesworth

3
"Negatif bir sayının" bu şekilde ayrıştırılmadığını hiç düşünmemiştim. Bir sebep görmüyorum. Umarım -1.0negatif bir çift değer olarak ayrıştırılır, değil mi?
leemes

6
@ qPCR4vir: Hayır. Cevabınıza yazdığım gibi, ne modern C ne de C ++ bu durumda imzasız türlerin kullanılmasına izin vermez ( karıştırılmamış bir ondalık sabit ile ). unsigned long intBu bağlamda yalnızca ilk standart C'ye (C89 / 90) izin verildi , ancak C99'da bu izin kaldırıldı. C ve C ++ 'da karıştırılmamış değişmez değerlerin imzalı türlere sahip olması gerekir . İmzalı bir tip işe yaradığında burada imzasız bir tür görürseniz, derleyiciniz bozuk demektir. İmzalı olmayan bir tür işe yaramazsa burada imzasız bir tür görürseniz, bu yalnızca tanımlanmamış davranışın belirli bir tezahürüdür.
AnT

43

Derleyici (VC2012) değerleri tutabilen "minimum" tamsayılara yükselir. İlk durumda, signed int(ve long int) (işaret uygulanmadan önce), ancak unsigned intolabilir: 2147483648varunsigned int ???? yazın. İkincisinde sen zorlamak intdan unsigned.

const bool i= (-2147483648 > 0) ;  //   --> true

Uyarı C4146: imzasız tipe tekli eksi operatör uygulandı , sonuç hala imzasız

İşte ilgili "meraklar":

const bool b= (-2147483647      > 0) ; //  false
const bool i= (-2147483648      > 0) ; //  true : result still unsigned
const bool c= ( INT_MIN-1       > 0) ; //  true :'-' int constant overflow
const bool f= ( 2147483647      > 0) ; //  true
const bool g= ( 2147483648      > 0) ; //  true
const bool d= ( INT_MAX+1       > 0) ; //  false:'+' int constant overflow
const bool j= ( int(-2147483648)> 0) ; //  false : 
const bool h= ( int(2147483648) > 0) ; //  false
const bool m= (-2147483648L     > 0) ; //  true 
const bool o= (-2147483648LL    > 0) ; //  false

C ++ 11 standardı :

2.14.2 Tamsayı değişmez değerler [lex.icon]

...

Tamsayı değişmez değeri, nokta veya üs parçası olmayan bir basamak dizisidir. Tamsayı değişmezinin temelini belirten bir öneki ve türünü belirten bir soneki olabilir.

...

Bir tam sayı değişmezinin türü, değerinin temsil edilebileceği karşılık gelen listenin ilkidir.

resim açıklamasını buraya girin

Bir tam sayı değişmezi, listesindeki herhangi bir türle temsil edilemiyorsa ve genişletilmiş bir tam sayı türü (3.9.1) değerini temsil edebilirse, bu genişletilmiş tam sayı türüne sahip olabilir. Listede hazır bilgi için tüm türler imzalanırsa, genişletilmiş tamsayı türü imzalanır. Listedeki değişmezler için tüm türler imzasızsa, genişletilmiş tamsayı türü imzasız olacaktır. Liste hem imzalı hem de imzasız türleri içeriyorsa, genişletilmiş tamsayı türü imzalı veya imzasız olabilir. Çeviri birimlerinden biri, izin verilen türlerin hiçbiri tarafından temsil edilemeyen bir tamsayı değişmezi içeriyorsa, program yanlış biçimlendirilmiştir.

Ve bunlar standarttaki tamsayıların promosyon kurallarıdır.

4.5 İntegral tanıtımları [conv.prom]

Başka bir tamsayıdır tip bir prvalue bool, char16_t, char32_tya da wchar_tolan bir tamsayı dönüşüm sıralaması (4.13) daha az int sıralaması daha tipte bir prvalue dönüştürülebilir intise int, kaynak türü bütün değerlerini temsil edebilir; Aksi takdirde, kaynak değer bir tür değere dönüştürülebilir unsigned int.


3
qPCR4vir @: In C89 / 90 derleyiciler kullanım tiplerine gerekiyordu int, long int, unsigned long intunsuffixed ondalık sabitlerini temsil etmek. Düzeltilmemiş ondalık sabitler için imzasız türlerin kullanılmasına izin veren tek dil buydu. C ++ 98'de intveya long int. İmzasız türe izin verilmiyor. Ne C (C99'dan başlayarak) ne de C ++, derleyicinin bu bağlamda imzasız türleri kullanmasına izin vermez. Elbette, imzalı olanlardan hiçbiri işe yaramazsa derleyiciniz imzasız türleri kullanmakta özgürdür, ancak bu hala tanımlanmamış davranışın belirli bir tezahürüdür.
AnT

@AndreyT. Harika! Elbette, gücün. VC2012 bozuk mu?
qPCR4vir

@ qPCR4vir: AFAIK, VC2012 henüz bir C ++ 11 derleyicisi değil (öyle mi?), yani temsil etmek için ya intda long inttemsil etmek zorunda 2147483648. Ayrıca, AFAIK, VC2012 intve long int32-bit tipleridir. Bu, VC2012'de değişmez değerin tanımlanmamış davranışa2147483648 yol açması gerektiği anlamına gelir . Davranış tanımlanmadığında derleyicinin herhangi bir şey yapmasına izin verilir. Bu, VC2012'nin kırık olmadığı anlamına gelir. Sadece yanıltıcı bir teşhis mesajı yayınladı. Davranışın tanımsız olduğunu söylemek yerine imzasız bir tip kullanmaya karar verdi.
AnT

@AndreyT: Kaynak kodu, imzalı bir işaretin maksimum değerini aşan ve tanı koyması gerekmeyen, sorgulanmamış bir ondalık değişmez değeri içeriyorsa derleyicilerin burun iblisleri yaymakta özgür olduğunu mu söylüyorsunuz long? Bu kırık görünüyordu.
supercat

Aynı "Uyarı C4146" VS2008 ve "bu ondalık sabit sadece ISO C90'da imzasız" G ++
spyder

6

Kısacası, 2147483648taşar -2147483648ve (-(-2147483648) > 0)olur true.

Bu nasıl 2147483648görünüyor ikilik sistemde gibi.

Ayrıca, imzalı ikili hesaplamalar durumunda, en önemli bit ("MSB") işaret bitidir. Bu soru nedenini açıklamaya yardımcı olabilir.


4

Çünkü -2147483648aslında 2147483648olumsuzlama ile ( -) uygulanmış, sayı beklediğiniz değil ne. Aslında bu sözde kodun eşdeğeridir:operator -(2147483648)

Şimdi, derleyici varsayarak sahiptir sizeof(int)eşit 4ve CHAR_BITolarak tanımlanır 8o yapacak, 2147483648bir tamsayı maksimum imzalı değeri taşma ( 2147483647). Peki maksimum artı olan nedir? 4 bit 2s iltifat tamsayı ile çalışalım.

Bekle! 8 tamsayıyı aşar! Biz ne yaptık? İşaretsiz 1000imzasını kullanın ve bitleri işaretli bir tamsayı olarak yorumlayın. Bu temsil bizi hepimizin bildiği gibi, daha büyük -8olan 2'li tamamlayıcı olumsuzluğun uygulanmasına bırakıyor .80

Bu nedenle <limits.h>(ve <climits>) yaygın INT_MINolarak ((-2147483647) - 1)- olarak tanımlanır , böylece maksimum işaretli tamsayı ( 0x7FFFFFFF) reddedilir ( 0x80000001), sonra azaltılır ( 0x80000000).


4 bitlik bir sayı için, ikisinin tamamlayıcı olumsuzlaması -8hala devam etmektedir -8.
Ben Voigt

Bunun dışında -8, negatif 8 değil 0-8 olarak yorumlanır ve 8, 4 bit imzalı bir int taşar
Cole Johnson

-(8)Hangi C ++ ile aynı olduğunu düşünün -8- negatif bir değişmeze değil, bir değişmeze uygulanan olumsuzlamadır. Değişmez, 8işaretli bir 4 bit tam sayıya sığmaz, bu nedenle işaretsiz olmalıdır. Desen 1000. Şimdiye kadar cevabınız doğru. İkisinin 10004 bitlik tamamlayıcı olumsuzluğu 1000, imzalanmış veya imzalanmamış olması önemli değil. Cevabınız, "bitleri işaretli bir tamsayı olarak yorumla" diyor ki bu -8, ikisinin tamamlayıcı olumsuzlamasından sonraki değeri , tıpkı olumsuzlamadan önceki gibi yapar.
Ben Voigt

Tabii ki, "4-bit C ++" hiçbir "bitleri işaretli bir tamsayı adımı olarak yorumlamak" yoktur. Değişmez, onu işaretleyebilen en küçük tür haline gelir, bu işaretsiz 4 bit tam sayıdır . Değişmez değer 8. Olumsuzluk uygulanır (modulo 16) 8. Kodlama hala 1000'dir, ancak işaretsiz bir tür seçildiği için değer farklıdır.
Ben Voigt
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.