2011-02-06 13 views
7

में "अनियंत्रित उपयोग" चेतावनी मैं चेतावनी स्तर -Wall -Wextra के साथ g ++ का उपयोग कर रहा हूं और चेतावनियों को त्रुटियों (-Werror) के रूप में उपयोग कर रहा हूं।जी ++ कंपाइलर

अब मुझे कभी-कभी त्रुटि मिल रही है "परिवर्तनीय इस फ़ंक्शन में अनियमित उपयोग किया जा सकता है"।

"कभी-कभी" मेरा मतलब है कि मेरे पास दो स्वतंत्र संकलन इकाइयां हैं जिनमें दोनों एक ही हेडर फ़ाइल शामिल हैं। एक संकलन इकाई त्रुटि के बिना संकलित करता है, दूसरा उपर्युक्त त्रुटि देता है।

हेडर फ़ाइलों में कोड का प्रासंगिक टुकड़ा निम्नानुसार है। चूंकि फ़ंक्शन बहुत लंबा है, इसलिए मैंने केवल नीचे प्रासंगिक बिट को पुन: उत्पन्न किया है।

सटीक त्रुटि है:

'cmpres' इस समारोह

में अप्रारंभीकृत इस्तेमाल किया जा सकता और मैं नीचे * द्वारा त्रुटि के साथ लाइन में चिह्नित किया है।

for (; ;) { 
    int cmpres; // * 
    while (b <= c and (cmpres = cmp(b, pivot)) <= 0) { 
     if (cmpres == 0) 
      ::std::iter_swap(a++, b); 
     ++b; 
    } 
    while (c >= b and (cmpres = cmp(c, pivot)) >= 0) { 
     if (cmpres == 0) 
      ::std::iter_swap(d--, c); 
     --c; 
    } 
    if (b > c) break; 
    ::std::iter_swap(b++, c--); 
} 

(cmp एक functor है कि दो संकेत x और y 0 या +1 लेता है और रिटर्न -1, अगर *x < *y, *x == *y या *x > *y क्रमशः। अन्य चर एक ही सरणी में संकेत दिए गए हैं है।)

कोड का यह टुकड़ा एक बड़े कार्य का हिस्सा है लेकिन परिवर्तनीय cmpres का उपयोग कहीं और है। इसलिए मैं समझने में असफल रहा कि यह चेतावनी क्यों उत्पन्न हुई है। इसके अलावा, संकलक स्पष्ट रूप से समझता है कि cmpres कभी भी प्रारंभ नहीं किया जाएगा (या कम से कम, यह हमेशा चेतावनी नहीं देता है, ऊपर देखें)।

  1. क्यों असंगत व्यवहार:

    अब मैं दो प्रश्न हैं? क्या यह चेतावनी एक ह्युरिस्टिक द्वारा उत्पन्न की गई है? (यह व्यवहार्य है क्योंकि इस चेतावनी को उत्सर्जित करने के लिए नियंत्रण प्रवाह विश्लेषण की आवश्यकता होती है जो सामान्य मामले में एनपी कठिन होता है और हमेशा नहीं किया जा सकता है।)

  2. चेतावनी क्यों? मेरा कोड असुरक्षित है? मैं इस विशेष चेतावनी की सराहना करने आया हूं क्योंकि उसने मुझे अन्य मामलों में बग का पता लगाने के लिए बहुत कठिन से बचाया है - इसलिए कम से कम कभी-कभी एक वैध चेतावनी है। क्या यह यहां वैध है?

+4

बस 'int cmpres = 0;' के लिए '(;;) 'लूप के बाहर' और अपने जीवन के साथ आगे बढ़ें;) – fredoverflow

+0

@Fred मेरी समस्या चेतावनी नहीं लेनी है, लेकिन यह देखने के लिए कि क्या चेतावनी वास्तव में * सही * है और मैं यह भी नोटिस करने के लिए बहुत मूर्ख हूं कि मेरे कोड में कोई त्रुटि है। –

उत्तर

12

एक एल्गोरिदम जो बिना किसी झूठी नकारात्मक या सकारात्मक के साथ अनियमित चर का निदान करता है (एक सबराउटिन के रूप में) में एक एल्गोरिदम शामिल होता है जो Halting Problem हल करता है। जिसका अर्थ है ऐसा कोई एल्गोरिदम नहीं है। कंप्यूटर के लिए यह असंभव है, जो इस समय 100% सही है।

मुझे नहीं पता कि जीसीसी का अनियंत्रित चर विश्लेषण वास्तव में कैसे काम करता है, लेकिन मुझे पता है कि कोड के प्रारंभिक अनुकूलन पास के लिए यह बहुत संवेदनशील है। इसलिए मुझे आश्चर्य नहीं है कि आपको कभी-कभी झूठी सकारात्मकता मिलती है। यह ऐसे मामलों में जहां यह ऐसे मामलों में जहां यह निश्चित नहीं हो सकते से निश्चित है भेद करता है -

int foo() { int a; return a; } 

पैदा करता है "चेतावनी: 'एक' इस समारोह में अप्रारंभीकृत प्रयोग किया जाता है" (जोर मेरा)।

संपादित करें: मैं एक मामले में जहां जीसीसी के हाल के संस्करण (4.3 और बाद में) असफल एक गैर-आरंभिकृत चर निदान करने के लिए मिला:

int foo(int x) 
{ 
    int a; 
    return x ? a : 0; 
} 

प्रारंभिक अनुकूलन देखा कि x अशून्य है अगर, समारोह के व्यवहार अपरिभाषित है, इसलिए मान लें x शून्य होना चाहिए और फ़ंक्शन के पूरे शरीर को "return 0;" से प्रतिस्थापित करें, यह उपयोग से पहले अनियमित चेतावनी उत्पन्न करने वाले पास से पहले होता है, इसलिए कोई निदान नहीं होता है। गोर विवरण के लिए GCC bug 18501 देखें।

मैं इसे आंशिक रूप से यह दिखाने के लिए लाता हूं कि उत्पादन-ग्रेड कंपाइलर अनियमित-परिवर्तनीय डायग्नोस्टिक्स दोनों तरीकों से गलत हो सकते हैं, और आंशिक रूप से क्योंकि यह इस बिंदु का एक अच्छा उदाहरण है कि अपरिभाषित व्यवहार निष्पादन समय में पिछड़ा प्रचार कर सकता है। x परीक्षण के बारे में कुछ भी अपरिभाषित नहीं है, लेकिन x पर कोड नियंत्रण-निर्भरता को अपरिभाषित व्यवहार है, इसलिए एक कंपाइलर को यह मानने की अनुमति है कि नियंत्रण निर्भरता कभी संतुष्ट नहीं होती है और परीक्षण को त्याग देती है।

+0

क्या आपके पास अपनी रोक समस्या का दावा है ? मेरा मतलब है, मैंने सवाल में एनपी-कठोरता खुद को बताया है (जो उस दावे के साथ संगत होगा) लेकिन मुझे आपके दावे के बारे में कम यकीन नहीं है। एल्गोरिदम वास्तव में प्रोग्राम प्रवाह को हल करने के लिए नहीं है, केवल इसे पुनर्निर्माण। - यह कहा, चेतावनी के शब्द के बारे में दिलचस्प जानकारी। –

+1

मेरे प्रश्न को अनदेखा करें। यह स्पष्ट है: संकलक को कुल शुद्धता (= लूप की समाप्ति) साबित करना होगा जो सीधे हल करने की समस्या का तात्पर्य है। –

2

कोड सही है, लेकिन संकलक यह पहचानने में असफल रहा है कि परिवर्तनीय प्रारंभ के बिना कभी भी उपयोग नहीं किया जाता है।

1

मैं सुझाव दूंगा कि यह एक मानवीय त्रुटि है- यही "मई" है। मुझे संदेह है कि कई लूप स्थितियां इस तरह दिखती नहीं हैं। वह कोड असुरक्षित नहीं है क्योंकि सभी नियंत्रण पथों में, cmpres उपयोग से पहले असाइन किया गया है। हालांकि, मुझे निश्चित रूप से इसे पहले शुरू करना गलत नहीं होगा।

हालांकि, आप यहां कुछ प्रकार के परिवर्तनीय छायांकन कर सकते हैं।यही एकमात्र स्पष्टीकरण होगा जो मैं दो अनुवाद इकाइयों में से केवल एक को त्रुटियों के बारे में सोच सकता हूं।

+0

बिंदु यह है कि, मुझे लगता है कि * अगर * यह एक उदारवादी है और संकलक हमेशा यह नहीं देखता है, तो चेतावनी वास्तव में उचित है (और एक तर्क त्रुटि को इंगित करता है), संकलक बस इसे हमेशा नहीं देखता है ... –

3

इस हफ्ते उन हेरिस्टिक से संबंधित क्लैंग देव-मेलिंग सूची पर एक दिलचस्प चर्चा हुई।

लब्बोलुआब यह है: यह घातीय व्यवहार प्राप्त किए बिना unitialized मूल्यों का निदान करने में वास्तव में काफी मुश्किल है ...

जाहिर

(चर्चा से), जीसीसी एक विधेय आधार दृष्टिकोण का उपयोग करता है, लेकिन अपने अनुभव को देखते हुए यह ऐसा लगता है कि हमेशा पर्याप्त नहीं है।

मुझे संदेह है कि इस तथ्य के साथ कुछ करने के लिए कुछ मिला है कि असाइनमेंट स्थिति के भीतर मिश्रित है (और उस पर एक शॉर्ट-सर्किट ऑपरेटर के बाद ...)। क्या आपने बिना कोशिश की है?

मुझे लगता है कि जीसीसी और क्लैंग लोगों दोनों इस उदाहरण से बहुत रुचि रखते हैं क्योंकि यह सी या सी ++ में अपेक्षाकृत सामान्य प्रथा है और इस प्रकार कुछ ट्यूनिंग से लाभ हो सकता है।

+0

जीसीसी और एसएसए कंपाइलर्स नहीं हैं? एक एसएसए संकलक कोड चर के अनुसार एकाधिक चर में एक चर को विभाजित करता है जिस पर इसका उपयोग किया जाता है। इस मामले में, एक एसएसए संकलक को दो शाखाओं के लिए दो में 'cmpres' विभाजित करना चाहिए था। दोनों शाखाओं में, एक पढ़ा जाता है जो असाइनमेंट का पालन करता है। – MSalters

+0

@MSalters: समस्या यह है कि जिस बिंदु पर आप एसएसए फॉर्म तक पहुंच चुके हैं, मुझे "असली" कोड पर वापस मैप करना मुश्किल है, जब मुझे लगता है कि आपके पास निदान है:/ –

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