2012-10-04 37 views
9
#include <stdio.h> 
#include <limits.h> 

void sanity_check(int x) 
{ 
    if (x < 0) 
    { 
     x = -x; 
    } 
    if (x == INT_MIN) 
    { 
     printf("%d == %d\n", x, INT_MIN); 
    } 
    else 
    { 
     printf("%d != %d\n", x, INT_MIN); 
    } 
    if (x < 0) 
    { 
     printf("negative number: %d\n", x); 
    } 
    else 
    { 
     printf("positive number: %d\n", x); 
    } 
} 

int main(void) 
{ 
    sanity_check(42); 
    sanity_check(-97); 
    sanity_check(INT_MIN); 
    return 0; 
} 

Ben gcc wtf.c yukarıdaki programı derlemek, ben beklenen çıktı alın: Ben gcc -O2 wtf.c ile program derleme Ancakgarip tamsayı davranışı O2

42 != -2147483648 
positive number: 42 
97 != -2147483648 
positive number: 97 
-2147483648 == -2147483648 
negative number: -2147483648 

, ben farklı bir çıkış elde :

42 != -2147483648 
positive number: 42 
97 != -2147483648 
positive number: 97 
-2147483648 != -2147483648 
positive number: -2147483648 

Son iki satıra dikkat edin. Dünyada ne var ne yok? Gcc 4.6.3 biraz fazla hevesle optimize mi?

(Ben de 4.6.3 ++ g ile bu test, ve ben aynı garip davranışları, dolayısıyla C++ etiketi gözlemledik.)

+0

, ama yine de o kadar deneyimli değil için yararlı olabilir. Yalnızca optimizasyon seviyesinin neden olduğu "garip" farklılıklar görüyorsam, ilk bakacağım şey UB'dir. – ThomasMore

cevap

15

Bunu yaptığınızda - (INT_MIN) Sonucun int sığamaz beri, tanımsız davranış yürütmesini ediyoruz. negatif olamaz x ve bundan sonra optimize

gcc-O2 fark eder. Değersiz olduğu için değeri aştığınız için umursamaz ve istediği gibi davranabilir.

muhtemelen çok daha deneyimli geliştirici için tavsiye vermek rahat hissetmiyorum
+0

Hiçbir şey, bir derleyicinin standarttaki UB'yi tanımlamaktan kaçınmasını engeller; örneğin, birbirini takip eden iki tamamlayıcı aritmetik. Öyleyse şaşılacak bir şey olmalı, iddia edilen optimizasyonu yapmanın * yararı nedir? Yok, görebildiğim kadarıyla. Bu bir aptalın optimizasyonu, IMHO. Bu yüzden, derleyici resmi olarak kendi hakları dahilinde olsa da, en azından bu bakımdan ** düşük kaliteli bir uygulama **. –

+2

pedr0 cevabında bir örnek var. Daha fazlası için, buraya bakın: http: //blog.llvm.org/2011/05/what-every-c-programmer-should-know.html # signed_overflow –

+0

link için çok teşekkürler! İlk iki paragrafın, "X'in Y yapmanın olası bir yolu olduğunu, dolayısıyla X'in Y için gerekli olduğunu" mantıksal yanlışlıkları kuvvetle ima ettiğini unutmayın. Bundan sonra okumayı bıraktım ... :-) –

12

Buradan, bu size yardımcı olabilecek düşünüyorum: here

-fstrict-overflow Derleyicinin, derlenmiş olan dile bağlı olarak sıkı imzalı taşma kuralları almasına izin ver. C (ve C++) için bu, imzalı sayılarla aritmetik yapılırken taşma işleminin tanımsız olduğu anlamına gelir, yani derleyici bunun olmayacağını varsayabilir. Bu çeşitli optimizasyonlara izin verir. Örneğin, derleyici i + 10> i gibi bir ifadenin her zaman imzalı i için doğru olacağını varsayacaktır. Bu varsayım, yalnızca ikilik tamamlama aritmetiği kullanıldığında i + 10 taşması durumunda ifade yanlış olduğu için, taşma taşması tanımlanmamışsa geçerlidir. Bu seçenek yürürlükte olduğunda, imzalı sayılar üzerindeki bir işlemin taşma işleminin gerçekte taşımıp içermediğine dikkatlice yazılmasının gerekip gerekmediğini belirlemek için herhangi bir girişimde bulunulmalıdır. Bu seçenek ayrıca derleyici sıkı işaretçi semantiğini üstlenmesini sağlamaktadır: Bir aynı nesneye bir işaretçi üretmek olmadığını pointer ofset eklenmesi durumunda, bir nesneye bir işaretçi verilen ilave tanımlanmamıştır. Bu, derleyicinin p + u> p'nin bir işaretçi p ve işaretsiz tamsayı için her zaman doğru olduğunu bildirmesine izin verir. Bu varsayım, yalnızca p + u, ikiye tamamlayıcı aritmetik kullanarak taşarsa, ifade yanlış olduğu için işaretçi sarma dosyasının tanımlanmamış olması nedeniyle geçerlidir.

da -fwrapv seçeneği bakınız. -fwrapv kullanımı, tamsayı imzalı taşmanın tam olarak tanımlandığı anlamına gelir: sarar. -fwrapv kullanıldığında, tamsayılar için -fstrict-overflow ve -fno-strict-overflow arasında fark yoktur. -fwrapv ile belirli taşma tiplerine izin verilir. Örneğin, derleyici sabitler üzerinde aritmetik yapılırken taşma alırsa, taşma değeri hala -fwrapv ile kullanılabilir, ancak başka şekilde değil.

-fstrict-taşma opsiyon seviyeleri O2, -o3 -OS de etkindir.