2012-10-04 24 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; 
} 

जब मैं gcc wtf.c साथ उपरोक्त कार्यक्रम संकलन, मैं उम्मीद आउटपुट प्राप्त:जीसीसी के साथ अजीब पूर्णांक व्यवहार -O2

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

हालांकि, जब मैं gcc -O2 wtf.c साथ कार्यक्रम संकलन, मुझे कोई दूसरी आउटपुट प्राप्त :

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

अंतिम दो पंक्तियों पर ध्यान दें। पृथ्वी पर क्या चल रहा है? जीसीसी 4.6.3 थोड़ा उत्सुकता से अनुकूलित कर रहा है?

(मैं भी ++ जी के साथ 4.6.3 इस परीक्षण किया है, और मैं एक ही अजीब व्यवहार, इसलिए सी ++ टैग मनाया।)

+0

संभवतः अधिक अनुभवी डेवलपर के लिए सलाह देने में सहज महसूस नहीं करता है, लेकिन फिर भी यह इतना अनुभवी नहीं हो सकता है। अगर मुझे केवल अनुकूलन स्तर के कारण "अजीब" मतभेद दिखाई देते हैं, तो पहली बात यह है कि मैं यूबी की तलाश करूंगा। – ThomasMore

उत्तर

15

जब आप करते हैं - (INT_MIN) आप अपरिभाषित व्यवहार का आह्वान कर रहे हैं, क्योंकि वह परिणाम int में फिट नहीं हो सकता है।

gcc -O2 नोटिस कि एक्स कभी नकारात्मक नहीं हो सकता है और उसके बाद अनुकूलित हो सकता है। यह परवाह नहीं करता है कि आपने मूल्य को अतिरंजित कर दिया है क्योंकि यह अनिर्धारित है और यह इसका इलाज कर सकता है हालांकि यह चाहता है।

+0

कुछ भी एक कंपाइलर को परिभाषित करने से रोकता है जो मानक में यूबी है, जैसे गैर-फँसाने वाले दो के पूरक अंकगणित। तो किसी को आश्चर्य होना चाहिए, कथित अनुकूलन करने का * लाभ * क्या है? कोई नहीं, जहां तक ​​मैं देख सकता हूं। यह एक मूर्खतापूर्ण अनुकूलन है, आईएमएचओ। इसलिए जब संकलक औपचारिक रूप से अपने अधिकारों के भीतर है, तो कम से कम इस संबंध में यह ** कम गुणवत्ता वाला कार्यान्वयन ** है। –

+2

pedr0 के उत्तर में एक उदाहरण है। कुछ और के लिए यहां देखें: http: //blog.llvm।संगठन/2011/05/क्या-हर-सी-प्रोग्रामर-चाहिए-know.html # sign_overflow –

+0

लिंक के लिए बहुत धन्यवाद! ध्यान दें कि पहले दो पैराग्राफ दृढ़ता से तर्कसंगत रूप से तर्क देते हैं कि "एक्स वाई करने का एक संभावित तरीका है, इसलिए X को वाई के लिए आवश्यक है"। मैंने उसके बाद पढ़ना बंद कर दिया ... :-) –

12

मुझे लगता है कि यह आपकी मदद कर सकता है, यहां से जाता है: here

-fstrict-overflow कंपाइलर संकलित भाषा के आधार पर सख्त हस्ताक्षरित ओवरफ्लो नियमों को मानने की अनुमति दें। सी (और सी ++) के लिए इसका मतलब है कि हस्ताक्षर संख्याओं के साथ अंकगणित करते समय अतिप्रवाह अनिर्धारित है, जिसका अर्थ है कि संकलक यह मान सकता है कि ऐसा नहीं होगा। यह विभिन्न अनुकूलन की अनुमति देता है। उदाहरण के लिए, कंपाइलर मान लेगा कि i + 10 जैसी अभिव्यक्ति> मैं हमेशा हस्ताक्षरित I के लिए सच रहूंगा। यह धारणा केवल तभी मान्य होती है जब हस्ताक्षरित ओवरफ़्लो अपरिभाषित हो, क्योंकि अभिव्यक्ति झूठी है यदि मैं दोहराव अर्धसूत्रीय का उपयोग करते समय 10 + बहती है। जब यह विकल्प प्रभावी रूप से यह निर्धारित करने का प्रयास करता है कि हस्ताक्षरित संख्याओं पर एक ऑपरेशन ओवरफ्लो को सावधानीपूर्वक लिखा जाना चाहिए ताकि वास्तव में अतिप्रवाह शामिल न हो। यह विकल्प संकलक को सख्त सूचक संकेतक मानने की अनुमति देता है: किसी ऑब्जेक्ट को पॉइंटर दिया जाता है, अगर उस पॉइंटर में ऑफसेट जोड़ना उसी ऑब्जेक्ट को पॉइंटर नहीं बनाता है, तो अतिरिक्त अपरिभाषित है। यह संकलक को निष्कर्ष निकालने की अनुमति देता है कि पी + u> पी ​​हमेशा एक सूचक पी और हस्ताक्षरित पूर्णांक के लिए सच है। यह धारणा केवल वैध है क्योंकि पॉइंटर रैपरराउंड अनिर्धारित है, क्योंकि अभिव्यक्ति झूठी है यदि पी + यू दोहरे पूरक अंकगणित का उपयोग कर बहती है।

-fwrapv विकल्प भी देखें। -फ्रैप्रव का उपयोग करना मतलब है कि पूर्णांक हस्ताक्षर ओवरफ्लो पूरी तरह से परिभाषित किया गया है: यह लपेटता है। जब -फ्रैवव का उपयोग किया जाता है, तो पूर्णांक के लिए -फिक्ट-ओवरफ्लो और -फनो-सख्त-ओवरफ़्लो के बीच कोई अंतर नहीं होता है। Ffrapv के साथ कुछ प्रकार के अतिप्रवाह की अनुमति है। उदाहरण के लिए, यदि कंपाइलर पर अंकगणित करते समय कंपाइलर ओवरफ्लो हो जाता है, तो अतिप्रवाह मूल्य अभी भी -फ्रैवव के साथ उपयोग किया जा सकता है, लेकिन अन्यथा नहीं।

-fstrict-overflow विकल्प स्तर -O2, -O3, -Os पर सक्षम है।

संबंधित मुद्दे