2012-09-18 16 views
5

Kısa bir süre önce kodumda hata ayıklamak için birkaç saatimi alan bir hata buldum.Belirli örtülü tür dönüşümleri neden bir makinede güvenli ve başka bir yerde değil? Bu çapraz platform sorunlarını nasıl önleyebilirim?

unsigned int foo(unsigned int i){ 
    long int v[]={i-1,i,i+1} ; 
     . 
     . 
     . 
return x ; // evaluated by the function but not essential how for this problem. 
} 

v tanımı imzasız int örtük vardı benim geliştirme makinede (ubuntu 12.04 32 bit, g ++ derleyici), üzerinde herhangi bir soruna neden olmadı:

sorun bir fonksiyonu olarak tanımlandı uzun int'ye dönüştürülür ve bu şekilde negatif değerler doğru bir şekilde ele alınmıştır.

Farklı bir makinede (ubuntu 12.04 64 bit, g ++ derleyici) bu işlem güvenli değildi. I = 0 olduğunda, v [0] -1 olarak ayarlanmadı, ancak bazı garip büyük değere (genellikle imzasız bir int negatif yapmaya çalışırken olur).

Uzun int

long int v[]={(long int) i - 1, (long int) i, (long int) i + 1}; 

i değişkeninin değerini döküm sorununu çözebilir ve her şeyi (her iki makinelerde) gayet güzel çalıştı.

İlk makinenin neden iyi çalıştığını anlayamıyorum ve diğer makinede çalışmaz.

Bunu anlamama yardımcı olabilir misiniz, böylece gelecekte bu veya diğer sorunlardan kaçınabileceğim için?

cevap

6

unsigned değerleri için, toplama/çıkarma, modulo aritmetiği olarak iyi tanımlanmıştır, bu nedenle 0U-1, std::numeric_limits<unsigned>::max() gibi bir şeye çalışır.

İşaretsizden imzalıya dönüştürülürken, hedef türü işaretsiz değerin tüm değerlerini tutacak kadar büyükse, o zaman basit bir şekilde hedef türüne doğru bir veri kopyası yapar. Hedef türü, tüm imzasız değerleri tutacak kadar büyük değilse, uygulamanın tanımlandığına inanıyorum (standart referansı bulmaya çalışır).

long 64-bit olduğunda (muhtemelen 64 bit makinenizde durum böyle) imzasız uyuyor ve düz kopyalanıyor.

long, 32 bit makinede 32 bit olduğunda, yine de büyük olasılıkla bit modelini, bu durumda -1 değeri olan işaretli bir değer olarak yorumlar.

DÜZENLEME: Bu sorunlardan kaçınmanın en kolay yolu, imzalı ve imzasız türlerin karıştırılmasını önlemektir. Kavramını negatif sayılara izin vermeyen bir değerden çıkarmak ne demektir? İşlev parametresinin örnekte imzalı bir değer olması gerektiğini tartışacağım.

Bu g ++ (en az sürüm 4.5), bu kodu özel kodunuzda algılayan kullanışlı bir -Wsign-conversion sağlar. Ayrıca tüm aşırı akışını yakalamak döküm uzman var olabilir

+0

Açıklama için teşekkürler, cevabınızı çok iyi anlayamadım.Tamamen emin değilim, ama uzun int imzasız int içerecek kadar büyük olduğunu hatırlıyorum (en azından online bulabileceğiniz bazı C++ referanslarına göre). Her neyse, onları karıştırmamak için iyi bir uygulama olduğuna katılıyorum, ama bu durumda benim için gerekli. Makine ile ilgili sorunların ne zaman ortaya çıkabileceğini merak ettim. – lucacerone

0

atmalarını: Oluşan tipi barındırabilir daha büyük numaralardan hata ayıklama atmalarını tüm yakalayacak bu kullanma

template<typename O, typename I> 
O architecture_cast(I x) { 
/* make sure I is an unsigned type. It */ 
static_assert(std::is_unsigned<I>::value, "Input value to architecture_cast has to be unsigned"); 

assert(x <= static_cast<typename std::make_unsigned<O>::type>(std::numeric_limits<O>::max())); 

return static_cast<O>(x); 
} 

. Bu, imzasız int 0 durumunuzu içerir ve -1 ile çıkarılır ve bu da en büyük imzasız int ile sonuçlanır.

İlgili konular