2009-10-20 12 views
18

C/C++ standardı (see this link)'a göre, C ve C++ içindeki >> işleç, zorunlu olarak imzalı sayılar için bir aritmetik kaydırma değildir. 0'ların (mantıksal) veya işaret biti (aritmetik) bitlerin sağa kaydırıldığı gibi kaydırılıp değiştirilmediği derleyici uygulamasına kalmıştır.C/C++ imzalı doğru kaymanın belirli bir derleyici için aritmetik olduğunu doğrulamak?

Bu kod, imzalı tamsayılar için mantıksal bir doğru kaydırmayı gerçekleştiren derleyiciler için derleme zamanında ASSERT (başarısızlık) işlevini yerine getirecek mi?

#define COMPILE_TIME_ASSERT(EXP) \ 
    typedef int CompileTimeAssertType##__LINE__[(EXP) ? 1 : -1] 

#define RIGHT_SHIFT_IS_ARITHMETIC \ 
    ((((signed int)-1)>>1) == ((signed int)-1)) 

// SHR must be arithmetic to use this code 
COMPILE_TIME_ASSERT(RIGHT_SHIFT_IS_ARITHMETIC); 
+3

Mantıksal bir geçişi kullanan bir makineye sahip olanlar için başarısız derlemeniz nedir? Yazılımınız neden böyle bir makinede/derleyicide kullanılamayacak? Kodu yazmak daha iyi olmaz mı ki imzalanmış bir sayının doğru kayması aritmetik mi yoksa mantıksal mı? –

+6

Bitsiz seçim yoluyla dalsız seçim (BFS) kullanıyorum. Çalışmak için aritmetik bir kayma gerektirir. COMPILE_TIME_ASSERT (RIGHT_SHIFT_IS_ARITHMETIC) koyuyorum; BFS başlığında. Kod, geleneksel veya dalsız yolları seçmek için RIGHT_SHIFT_IS_ARITHMETIC tanımını kullanmalıdır. Şube yanlış tahmin cezaları nedeniyle şube-serbest kod kullanmak için PS3/XBOX360 CPU'ların devasa bir hızlanma olabilir. – Adisak

+1

BTW, bir derleme zamanında başarısız derleme, açık bir şekilde belirtildiği yerde, kodun gizemli bir şekilde başarısız olmasından daha iyidir ... temel olarak, bu rutinlerin bu derleyici (veya CPU) tarafından desteklenmediğini söyleyecektir. – Adisak

cevap

6

Bana iyi görünüyor! Ayrıca derleyiciyi bir derleme dosyası (ya da derlenmiş programı hata ayıklayıcısına yükler) yayınlayacak şekilde ayarlayabilir ve signed int i; i >> 1; için hangi kodun yandığını görebilir, ancak çözümünüz gibi otomatik değildir.

İmzalı bir sayının aritmetik doğru kaymasını uygulamayan bir derleyici bulursanız, bunu duymak isterim.

+0

Evet, ben temel olarak otomatik olarak istiyorum ... opcodes'e bakmak bu gereksinim için makul bir beklenti değildir çünkü diğer ekiplerin çeşitli platformlarda kullanabileceği bir kütüphanede kullanıyorum. – Adisak

+0

[UNISYS 2200 sistemi] (http://stackoverflow.com/a/12277974/995714) için derleyici imzalı türler için mantıksal doğru kaydırmayı kullanır. "E1 >> E2 ifadesinin sonucu, E1'in (bir bit deseni olarak yorumlanır) sağ E2 bit konumlarına kaydırılmasıdır. E1 de olsa sağ kaydırma * mantıksaldır (solda sıfır doldurulur) ifade, işaretli bir tamsayı türüdür *. http://public.support.unisys.com/2200/docs/cp14.0/pdf/78310422-011.pdf –

1

Neden savunuyorsunuz? Derleyicinizin vardiya operatörünüz ihtiyaçlarınızı karşılamıyorsa, sonucu genişleterek durumu iyice çözebilirsiniz. Ayrıca, bazen çalışma zamanı yeterlidir. Sonuçta, derleyici'nın iyileştirici çalışma zamanın dışında derleme zamanı yapabilirsiniz: shift_is_arithmetictrue olması garanti edilirse, değer her derleyici tuz ortadan kaldıracaktır böylece

static const bool
template <typename Number> 
inline Number shift_logical_right(Number value, size_t bits) 
{ 
    static const bool shift_is_arithmetic = (Number(-1) >> 1) == Number(-1); 
    const bool negative = value < 0; 
    value >>= bits; 
    if (!shift_is_arithmetic && negative) // sign extend 
     value |= -(Number(1) << (sizeof(Number) * 8 - bits)); 
} 

, derleme zamanında değerlendirilebilir if tümcede ve const bool negative kodunun ölü kod olarak yapılması.

Not: kod, Mono'nun encode_sleb128 işlevinden uyarlanmıştır: here.

Güncelleme

gerçekten aritmetik kayması olmadan makinelerde derleme iptal etmek istiyorsanız, sen önişlemcisinden güvenerek değil hala kapalı daha iyi. Sen static_assert (veya BOOST_STATIC_ASSERT) kullanabilirsiniz: çeşitli yorumlarla itibaren

static_assert((Number(-1) >> 1) == Number(-1), "Arithmetic shift unsupported."); 
+0

Sadece mantıklı olan birçok kod var (örneğin, Maskeleri Kullanarak Şube Serbest Seçim). aritmetik işaretli vardiya ile derleyicilerde kullanmak. Üzerindeki aritmetik bir kaymanın zarif bir şekilde taklit edilmesi muhtemelen orijinal koddan önemli ölçüde daha yavaş olacaktır ve bu nedenle "optimizasyon" ortadan kalkar. – Adisak

+0

Yeterince adil. Yine de, ikinci nokta hala geçerli: önişlemciye güvenme. Güncellemeye bakın. – marton78

+1

static_assert(), C++ 11x'dir ve artırmayı kullanamıyoruz. Ama yaptığım çek ön işlemciye güvenmiyor, ben sadece aşağıdakileri yapabilirdim ama yazdığım örnekten daha okumak ve anlamak çok daha zor: 'typedef int CompileTimeAssertArithmeticShift [(((im int) -1) >> 1) == ((imzalı int) -1))? 1: -1]; ' – Adisak

0

, bu çapraz platformunu kullanarak bahsediyor. Derleyicilerinizin bir platform için derlediklerinde, derleme zamanı operatörlerinin çalışma zamanı olanlarla aynı davranacağını garanti ettiğinden emin olun.

Farklı davranışlara örnek olarak, kayan nokta sayıları bulunabilir. Derleyiciniz, int dönüşüne geri dönüyorsanız, sabit, bağımsız ifadesini tek, çift veya genişletilmiş olarak mı yapıyor?

constexpr int a = 41; constexpr int b = (a/7.5);

Demek istediğim, birçok farklı mimaride çalışırken derleyicilerinizin çalışma zamanı sırasında derleme zamanı olarak aynı davranışı garanti ettiğinden emin olmanız gerekir.

Bir derleyicinin dahili olarak imzalayabildiği ancak hedef üzerindeki amaçlanan işlem (ler) ini üretemeyeceği tamamen olasıdır. Emin olmanın tek yolu, çalışma zamanında test etmek veya montaj çıkışına bakmaktır.

Montaj çıktısına bakmak dünyanın sonu değil ... Kaç tane farklı platform var? Bu çok kritik bir performans olduğundan, 5 farklı mimariye yönelik 1-3 satırlık montajcı çıkışına bakmanın "işini" yapın.Çizginizi bulmak için tüm montaj çıktısına (genellikle!) Dalmak zorunda değilsiniz. Yapması çok ama çok kolay.

İlgili konular