एक संकलक का निर्माण करना असंभव क्यों है जो यह निर्धारित कर सकता है कि क्या C ++ फ़ंक्शन किसी विशेष चर के मूल्य को बदल देगा?


104

मैंने इस पंक्ति को एक पुस्तक में पढ़ा:

एक संकलक का निर्माण करना असंभव है जो वास्तव में यह निर्धारित कर सकता है कि सी ++ फ़ंक्शन किसी विशेष चर के मूल्य को बदल देगा या नहीं।

पैराग्राफ के बारे में बात कर रहा था कि कॉन्सल-नेस की जांच करते समय कंपाइलर क्यों रूढ़िवादी है।

ऐसे संकलक का निर्माण करना असंभव क्यों है?

कंपाइलर हमेशा जाँच कर सकता है कि क्या एक चर को फिर से असाइन किया गया है, इस पर एक गैर-कांस्ट फ़ंक्शन को लागू किया जा रहा है, या यदि इसे एक नॉन-कास्ट पैरामीटर के रूप में पास किया जा रहा है ...


24
पहली बात जो मेरे दिमाग में आती है वह है डायनेमिक लिंक लाइब्रेरी। अगर मैं अपनी मशीन पर कोड संकलित करता हूं, और आप अपनी मशीन पर कोड संकलित करते हैं, और हम उन्हें रन टाइम पर लिंक करते हैं , तो मैं आपके कंपाइलर को कैसे पता कर सकता हूं कि मैंने चर संशोधित किए हैं या नहीं?
मूइंग डक

4
@MooingDuck बिल्कुल सही। अधिक मोटे तौर पर, कंपाइलर व्यक्तिगत रूप से फ़ंक्शन को संकलित नहीं करता है, लेकिन इसे एक व्यापक चित्र के हिस्से के रूप में संकलित करता है जो सभी संकलक के दायरे में नहीं हो सकता है।
2voyage

3
"असंभव" एक अतिरंजना हो सकती है - "कम्प्यूटेशनल रूप से अनम्य" (जैसा कि एनपी-हार्ड में) एक बेहतर लक्षण वर्णन हो सकता है, लेकिन छात्र को समझाना थोड़ा कठिन है। एक लिंक की गई सूची या अन्य सार डेटा संरचना की कल्पना करें। यदि मैं उस फ़ंक्शन / ट्री / में एक नोड को बदलने वाले फ़ंक्शन को कॉल करता हूं / जो भी हो, तो एक कंपाइलर कभी भी यह साबित करने की उम्मीद कर सकता है कि कौन सा नोड संशोधित हुआ (और शायद अधिक महत्वपूर्ण बात, जो कि नहीं था) मूल रूप से कार्यक्रम के साथ पूरी तरह से अनुकरण किए बिना। अपेक्षित इनपुट, सभी को एक स्रोत फ़ाइल संकलित करने में 3 दिन का समय नहीं लगता ...
Twalberg

36
@twalberg इम्पॉसिबल एक ओवरस्टेटमेंट नहीं है, हाल्टिंग प्रॉब्लम यहां लागू होती है क्योंकि कई उत्तर बताते हैं। यह एक सामान्य कार्यक्रम का एल्गोरिदम को पूरी तरह से विश्लेषण करना संभव नहीं है।
फिकट

5
@twalberg Compilers जो केवल वैध कार्यक्रमों के सबसेट को संकलित करते हैं वे बहुत उपयोगी नहीं हैं।
कालेब

जवाबों:


139

ऐसे संकलक का निर्माण करना असंभव क्यों है?

उसी कारण से आप एक प्रोग्राम नहीं लिख सकते हैं जो यह निर्धारित करेगा कि क्या कोई भी प्रोग्राम समाप्त हो जाएगा। इसे रुकने की समस्या के रूप में जाना जाता है , और यह उन चीजों में से एक है, जो गणना योग्य नहीं हैं।

स्पष्ट होने के लिए, आप एक संकलक लिख सकते हैं जो यह निर्धारित कर सकता है कि एक फ़ंक्शन कुछ मामलों में परिवर्तनशील परिवर्तन करता है , लेकिन आप एक ऐसा नहीं लिख सकते जो आपको विश्वसनीय रूप से यह बताए कि फ़ंक्शन चर (या पड़ाव) को बदल देगा या नहीं। हर संभव समारोह।

यहाँ एक आसान उदाहरण है:

void foo() {
    if (bar() == 0) this->a = 1;
}

एक कंपाइलर कैसे निर्धारित कर सकता है, सिर्फ उस कोड को देखकर, क्या fooकभी बदलाव होगा a? यह कार्य के लिए बाहरी परिस्थितियों पर निर्भर करता है या नहीं, अर्थात् के कार्यान्वयन bar। इस प्रमाण से अधिक है कि रुकने की समस्या गणना योग्य नहीं है, लेकिन यह पहले से ही लिंक किए गए विकिपीडिया लेख (और प्रत्येक गणना सिद्धांत पाठ्यपुस्तक) में अच्छी तरह से समझाया गया है, इसलिए मैं इसे यहाँ सही ढंग से समझाने का प्रयास नहीं करूँगा।


48
@mrsoltys, क्वांटम कंप्यूटर कुछ समस्याओं के लिए तेजी से "केवल" हैं, वे अयोग्य समस्याओं को हल नहीं कर सकते हैं।
18

8
@mrsoltys वे घातीय जटिल एल्गोरिदम (फैक्टरिंग की तरह) क्वांटम कंप्यूटर के लिए एकदम सही है, लेकिन समस्या को हल करना एक तार्किक दुविधा है, यह कोई मायने नहीं रखता है कि आपके पास "कंप्यूटर" किस तरह का है।
user1032613

7
@mrsoltys, सिर्फ एक स्मार्ट बनने के लिए, हाँ, यह बदल जाएगा। दुर्भाग्य से, इसका मतलब यह होगा कि एल्गोरिथ्म दोनों समाप्त हो गया है और अभी भी चल रहा है, दुर्भाग्य से, आप यह नहीं बता सकते कि कौन सा प्रत्यक्ष रूप से अवलोकन किए बिना, जिससे आप वास्तविक स्थिति को प्रभावित करते हैं।
नाथन अर्नस्ट

9
@ ThorbjørnRavnAndersen: ठीक है, तो, मान लीजिए मैं एक कार्यक्रम को अंजाम दे रहा हूं। मैं वास्तव में यह कैसे निर्धारित करूं कि यह समाप्त हो जाएगा?
रुख

8
@ ThorbjørnRavnAndersen लेकिन अगर आप वास्तव में कार्यक्रम को अंजाम देते हैं, और यह समाप्त नहीं होता है (जैसे एक अनंत लूप), तो आप कभी भी यह नहीं जान पाएंगे कि यह समाप्त नहीं होता है ... आप बस एक और कदम पर अमल करते रहते हैं, क्योंकि यह हो सकता है अंतिम एक ...
मैक्सएक्सहैक्स

124

कल्पना कीजिए कि ऐसा कंपाइलर मौजूद है। चलो यह भी मानते हैं कि सुविधा के लिए यह एक लाइब्रेरी फ़ंक्शन प्रदान करता है जो 1 रिटर्न देता है यदि पारित फ़ंक्शन किसी दिए गए चर और 0 को संशोधित करता है जब फ़ंक्शन नहीं करता है। फिर इस कार्यक्रम को क्या छापना चाहिए?

int variable = 0;

void f() {
    if (modifies_variable(f, variable)) {
        /* do nothing */
    } else {
        /* modify variable */
        variable = 1;
    }
}

int main(int argc, char **argv) {
    if (modifies_variable(f, variable)) {
        printf("Modifies variable\n");
    } else {
        printf("Does not modify variable\n");
    }

    return 0;
}

12
अच्छा! मैं एक झूठा विरोधाभास हूँ के रूप में एक प्रोग्रामर ने लिखा है।
क्रुमेलुर

28
यह वास्तव में हाल्टिंग समस्या की अनिर्वायता के लिए प्रसिद्ध प्रमाण का सिर्फ एक अच्छा रूपांतरण है
कॉन्सटेंटिन वीट्ज

10
इस ठोस मामले में "modifies_variable" को वापस लौटना चाहिए: कम से कम एक निष्पादन पथ है जिसमें चर वास्तव में संशोधित होता है। और उस निष्पादन पथ को एक बाहरी, गैर-नियतात्मक कार्य के लिए एक कॉल के बाद पहुंचा जाता है - इसलिए संपूर्ण कार्य गैर-निर्धारक है। इन 2 कारणों से, कंपाइलर को पेसिमिस्टिक व्यू लेना चाहिए और यह तय करना चाहिए कि यह वेरिएबल में बदलाव करे। यदि चर को संशोधित करने का मार्ग नियतात्मक तुलना (संकलक द्वारा सत्यापित) के बाद पहुंच जाता है, तो गलत (यानी "" 1 = 1 ") पैदावार होती है, तब संकलक सुरक्षित रूप से कह सकता है कि ऐसा फ़ंक्शन कभी चर को संशोधित नहीं करता है
जो Pineda

6
@JoePineda: सवाल यह है कि क्या fचर को संशोधित करता है - यह नहीं कि क्या यह चर को संशोधित कर सकता है। यह उत्तर सही है।
नील जी

4
@JoePineda: कुछ भी मुझे modifies_variableसंकलक स्रोत से कोड को कॉपी / पेस्ट करने से रोकता है , आपके तर्क को पूरी तरह से अशक्त करता है। (ओपन-सोर्स मानते हुए, लेकिन बात स्पष्ट होनी चाहिए)
orlp

60

"इनपुट के लिए " एक निष्पादन पथ है जो एक चर को संशोधित करता है जो "दिए गए चर को संशोधित करेगा या नहीं करेगा" भ्रमित न करें

पूर्व को अपारदर्शी विधेय निर्धारण कहा जाता है , और निर्णय लेने के लिए तुच्छ रूप से असंभव है - एक तरफ हॉल्टिंग समस्या से कमी से, आप बस यह बता सकते हैं कि इनपुट अज्ञात स्रोत (जैसे उपयोगकर्ता) से आ सकते हैं। यह सभी भाषाओं का सच है , न कि केवल C ++।

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

इसलिए, C ++ के बारे में एक आश्चर्यजनक कथन प्रतीत होता है जो वास्तव में सभी भाषाओं के बारे में एक तुच्छ कथन है।


5
यह सबसे अच्छा उत्तर imho है, यह महत्वपूर्ण है कि अंतर करना।
अंकलजीव

"तुच्छ असंभव"?
किप

2
@ किप "निश्चयपूर्वक असंभव" का अर्थ है "शायद का अर्थ है" निर्णय करना असंभव है, और प्रमाण तुच्छ है।
फ्रेडओवरफ़्लो

28

मुझे लगता है कि "C ++ फ़ंक्शन एक विशेष चर का मान बदल जाएगा या नहीं" में मुख्य शब्द "विल" है। एक संकलक का निर्माण करना निश्चित रूप से संभव है जो यह जाँचता है कि किसी विशेष चर के मान को बदलने के लिए C ++ फ़ंक्शन की अनुमति है या नहीं , आप निश्चितता के साथ यह नहीं कह सकते कि परिवर्तन होने जा रहा है:

void maybe(int& val) {
    cout << "Should I change value? [Y/N] >";
    string reply;
    cin >> reply;
    if (reply == "Y") {
        val = 42;
    }
}

"यह निश्चित रूप से एक संकलक का निर्माण करना संभव है जो यह जांचता है कि क्या C ++ फ़ंक्शन किसी विशेष चर के मान को बदल सकता है या नहीं" नहीं, यह नहीं है। देखें कालेब का जवाब एक कंपाइलर के लिए यह जानने के लिए कि क्या फू (a) बदल सकता है, यह जानना होगा कि क्या बार () को वापस करना संभव है। और ऐसा कोई कंप्युटेबल फंक्शन नहीं है जो किसी कंप्यूटेबल फंक्शन के सभी संभावित रिटर्न वैल्यू को बता सके। इसलिए ऐसे कोड पथ मौजूद हैं, जो संकलक यह बताने में सक्षम नहीं होंगे कि क्या वे कभी पहुंच पाएंगे। यदि एक चर को केवल एक कोड पथ में बदल दिया जाता है, जिस तक नहीं पहुंचा जा सकता है तो वह नहीं बदलेगा, लेकिन एक संकलक इसका पता नहीं लगाएगा
मार्टिन एप्स जूल

12
@MartinEpsz "द्वारा" मेरा मतलब है "को बदलने की अनुमति है", "संभवतः बदल सकता है" नहीं। मुझे विश्वास है कि जब-जब constजाँच की बात होती है, तब ओपी के दिमाग में यही होता है ।
dasblinkenlight

@dasblinkenlight मुझे इस बात से सहमत होना पड़ेगा कि मेरा मानना ​​है कि ओपी का मतलब पहले वाला हो सकता है, "ओ परिवर्तन की अनुमति है", या "बनाम" बदल सकता है या नहीं "निश्चित रूप से नहीं बदलेगा"। बेशक मैं एक परिदृश्य के बारे में नहीं सोच सकता, जहां यह एक मुद्दा होगा। आप किसी भी फ़ंक्शन पर पहचानकर्ता या "फ़ंक्शन को" परिवर्तन "विशेषता" वाले फ़ंक्शन को कॉल करने वाले किसी भी फ़ंक्शन पर बस "उत्तर में परिवर्तन" कर सकते हैं। कहा कि, C और C ++ के साथ यह कोशिश करने के लिए भयानक भाषाएं हैं, क्योंकि उनके पास चीजों की ऐसी ढीली परिभाषा है। मुझे लगता है कि यही कारण है कि कॉन्स्ट-नेस सी ++ में एक मुद्दा होगा।
DDS

@MartinEpsz: "और कोई कम्प्यूटेशनल फ़ंक्शन नहीं है जो किसी भी कम्प्यूटेशनल फ़ंक्शन के सभी संभावित रिटर्न मानों को बता सके"। मुझे लगता है कि "सभी संभावित रिटर्न मान" की जाँच करना एक गलत दृष्टिकोण है। गणितीय प्रणाली (मैक्सिमा, मैथलैब) हैं जो समीकरणों को हल कर सकती हैं, जिसका अर्थ है कि यह फ़ंक्शन के समान दृष्टिकोण को लागू करने के लिए समझ में आएगा। यानी इसे कई अनजान लोगों के साथ एक समीकरण के रूप में माना जाता है। समस्याओं का प्रवाह नियंत्रण + साइड इफेक्ट्स => असम्भव स्थितियाँ हैं। IMO, उन (कार्यात्मक भाषा, कोई असाइनमेंट / साइड इफेक्ट्स) के बिना, यह भविष्यवाणी करना संभव होगा कि कौन सा पथ कार्यक्रम लेगा
SigTerm

16

मुझे नहीं लगता कि यह बताने के लिए कि समस्या को समझने के लिए हॉल्टिंग समस्या को लागू करना आवश्यक है, आप संकलित समय पर यह नहीं जान सकते हैं कि दिए गए फ़ंक्शन एक निश्चित चर को संशोधित करेंगे या नहीं।

इसके बजाय, यह इंगित करने के लिए पर्याप्त है कि एक फ़ंक्शन का व्यवहार अक्सर रन-टाइम स्थितियों पर निर्भर करता है, जिसके बारे में कंपाइलर को पहले से पता नहीं चल सकता है। उदाहरण के लिए

int y;

int main(int argc, char *argv[]) {
   if (argc > 2) y++;
}

संकलक निश्चितता के साथ भविष्यवाणी कैसे कर सकता है कि क्या yसंशोधित किया जाएगा?


7

यह किया जा सकता है और संकलक इसे कुछ कार्यों के लिए हर समय कर रहे हैं , उदाहरण के लिए यह सरल इनलाइन एक्सेसर्स या कई शुद्ध कार्यों के लिए एक तुच्छ अनुकूलन है।

सामान्य मामले में इसे जानना असंभव है।

जब भी कोई सिस्टम कॉल या किसी अन्य मॉड्यूल से आने वाला फ़ंक्शन कॉल होता है, या संभावित ओवरराइड विधि के लिए कॉल होता है, तो कुछ भी हो सकता है, एक असंबंधित चर को बदलने के लिए स्टैक ओवरफ़्लो के कुछ हैकर के उपयोग से शत्रुतापूर्ण अधिग्रहण शामिल है।

हालाँकि, आपको कास्ट का उपयोग करना चाहिए, ग्लोबल्स से बचना चाहिए, पॉइंटर्स के संदर्भों को प्राथमिकता देना चाहिए, असंबंधित कार्यों के लिए वैरिएबल को फिर से उपयोग करने से बचना चाहिए, जो आक्रामक अनुकूलन करते समय कंपाइलर के जीवन को आसान बना देगा।


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

ओवरलोडिंग एक संकलन-समय की अवधारणा है। आप शायद "ओवरराइड विधि" का मतलब था।
22 मई

@FredOverflow: हाँ, मेरा मतलब है ओवरराइड। ओवरलोडिंग वास्तव में एक संकलन समय की अवधारणा है। इसे स्पॉट करने के लिए धन्यवाद (बेशक यदि कार्यान्वयन किसी अन्य संकलन इकाई से आता है, तो कंपाइलर को अभी भी इसका विश्लेषण करने में परेशानी हो सकती है, लेकिन यह मेरा मतलब नहीं था)। मैं जवाब ठीक कर दूंगा।
क्रिश

6

इसे समझाने के कई रास्ते हैं, जिनमें से एक हैलिंग समस्या :

कम्प्यूटेबिलिटी सिद्धांत में, हॉल्टिंग समस्या को निम्नानुसार कहा जा सकता है: "एक मनमाना कंप्यूटर प्रोग्राम के विवरण को देखते हुए, यह तय करें कि क्या प्रोग्राम चल रहा है या हमेशा के लिए जारी है"। यह निर्णय लेने की समस्या के बराबर है, एक प्रोग्राम और एक इनपुट दिया जाता है, क्या प्रोग्राम उस इनपुट के साथ चलने पर अंततः रुक जाएगा, या हमेशा के लिए चलेगा।

एलन ट्यूरिंग ने 1936 में साबित कर दिया कि सभी संभावित प्रोग्राम-इनपुट जोड़े के लिए हॉल्टिंग समस्या को हल करने के लिए एक सामान्य एल्गोरिदम मौजूद नहीं हो सकता है।

अगर मैं एक प्रोग्राम लिखूं जो इस तरह दिखता है:

do tons of complex stuff
if (condition on result of complex stuff)
{
    change value of x
}
else
{
    do not change value of x
}

क्या xपरिवर्तन का मूल्य है ? यह निर्धारित करने के लिए, आपको पहले यह निर्धारित करना होगा कि क्या do tons of complex stuffहिस्सा आग का कारण बनता है - या इससे भी अधिक बुनियादी, चाहे वह रुका हो। ऐसा कुछ है जो कंपाइलर नहीं कर सकता है।


6

वास्तव में आश्चर्य की बात है कि वहाँ कोई जवाब नहीं है कि सीधे समस्या को रोकने का उपयोग कर रहा है! इस समस्या को रोकने की समस्या के लिए बहुत सीधी कमी है।

कल्पना कीजिए कि संकलक बता सकता है कि किसी फ़ंक्शन ने किसी चर का मान बदल दिया है या नहीं। फिर यह निश्चित रूप से यह बताने में सक्षम होगा कि निम्नलिखित फ़ंक्शन y के मूल्य को बदलता है या नहीं, यह मानते हुए कि पूरे कार्यक्रम में x के मूल्य को सभी कॉल में ट्रैक किया जा सकता है:

foo(int x){
   if(x)
       y=1;
}

अब, किसी भी कार्यक्रम के लिए हम इसे पसंद करते हैं:

int y;
main(){
    int x;
    ...
    run the program normally
    ...
    foo(x);
}

ध्यान दें कि, यदि, और केवल अगर, हमारे कार्यक्रम में y का मूल्य बदल जाता है, तो क्या यह समाप्त हो जाता है - foo () आखिरी चीज है जो बाहर निकलने से पहले करती है। इसका मतलब है कि हमने हल करने की समस्या को हल कर दिया है!

उपरोक्त कमी से हमें पता चलता है कि यह निर्धारित करने की समस्या है कि किसी चर के मूल्य में परिवर्तन कम से कम कितना कठिन है। रुकने की समस्या को विवादित माना जाता है, इसलिए यह भी होना चाहिए।


मुझे यकीन नहीं है कि मैं आपके तर्क का पालन करता हूं, इस बारे में कि हमारा कार्यक्रम क्यों समाप्त होता है यदि यह मान बदलता है y। मुझे foo()जल्दी रिटर्न की तरह दिखता है , और फिर main()बाहर निकलता है। (इसके अलावा, आप foo()एक तर्क के बिना बुला रहे हैं ... यह मेरी उलझन का हिस्सा है।)
लार्स

1
@ लार्स: Iff संशोधित कार्यक्रम को समाप्त करता है, अंतिम फ़ंक्शन जिसे f कहा गया था। यदि y को संशोधित किया गया था, तो f को बुलाया गया था (अन्य कथन y को बदल नहीं सकते हैं, क्योंकि यह केवल संशोधन द्वारा पेश किया गया था)। इसलिए, यदि y संशोधित किया गया था, तो कार्यक्रम समाप्त हो गया।
MSalters

4

जैसे ही कोई फ़ंक्शन किसी अन्य फ़ंक्शन को कॉल करता है, जो संकलक के स्रोत को "नहीं" देखता है, उसे या तो यह मान लेना होगा कि चर बदल गया है, या चीजें आगे अच्छी तरह से गलत हो सकती हैं। उदाहरण के लिए, मान लें कि हमारे पास "foo.cpp" है:

 void foo(int& x)
 {
    ifstream f("f.dat", ifstream::binary);
    f.read((char *)&x, sizeof(x));
 }

और हमारे पास "bar.cpp" में है:

void bar(int& x)
{
  foo(x);
}

कंपाइलर "पता" कैसे xबदल रहा है (या आईएस बदल रहा है, अधिक उचित रूप से) bar?

मुझे यकीन है कि हम कुछ और जटिल हो सकते हैं, अगर यह पर्याप्त जटिल नहीं है।


कंपाइलर जान सकता है कि अगर बार x पास-पास-रेफरेंस-टू-कॉन्स्ट के रूप में पास किया गया है तो x बार में नहीं बदल रहा है, है ना?
क्रिकेटर

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

@MatsPetersson: मेरा मानना ​​है कि यदि आप कॉन्स्टैक करते हैं तो आपको उन सभी टुकड़ों को रखने के लिए मिलता है जो टूट जाते हैं क्योंकि कंपाइलर हो सकता है, लेकिन उसके लिए क्षतिपूर्ति नहीं करनी है।
ज़ैन लिंक्स

@ZanLynx: हाँ, मुझे यकीन है कि यह सही है। लेकिन एक ही समय में, कलाकारों का अस्तित्व होता है, जिसका अर्थ है कि किसी व्यक्ति ने भाषा को डिजाइन किया था, जिसके पास यह विचार था कि "हमें कुछ बिंदु पर इसकी आवश्यकता हो सकती है" - जिसका अर्थ है कि यह बिल्कुल भी उपयोगी नहीं है।
मैट पीटरसन

1

कंपाइलर के लिए यह निर्धारित करना असंभव है कि चर को बदल दिया जाएगा , जैसा कि बताया गया है।

कॉन्स्ट-नेस की जांच करते समय, ब्याज का सवाल ऐसा लगता है कि क्या किसी फ़ंक्शन द्वारा वेरिएबल को बदला जा सकता है। यहां तक ​​कि यह उन भाषाओं में कठिन है जो पॉइंटर्स का समर्थन करते हैं। आप किसी अन्य कोड को पॉइंटर से नियंत्रित नहीं कर सकते हैं, इसे किसी बाहरी स्रोत (हालांकि असंभावित) से भी पढ़ा जा सकता है। ऐसी भाषाओं में, जो मेमोरी तक पहुंच को प्रतिबंधित करती हैं, इस प्रकार की गारंटी संभव है और C ++ की तुलना में अधिक आक्रामक अनुकूलन की अनुमति देता है।


2
एक बात जो मैं चाहता था कि भाषाओं का समर्थन किया गया था वह पंचांग, ​​वापसी योग्य और लगातार संदर्भों (या बिंदु) के बीच अंतर होगा। पंचांग संदर्भों को केवल अन्य पंचांग संदर्भों के लिए कॉपी किया जा सकता है, वापसी योग्य लोगों को पंचांगों या प्रतिदेय लोगों की नकल किया जा सकता है, और लगातार लोगों को किसी भी तरह से कॉपी किया जा सकता है। किसी फ़ंक्शन का रिटर्न मान "रिटर्नेबल" मापदंडों के रूप में पारित होने वाले तर्कों के सबसे अधिक प्रतिबंध से विवश होगा। मैं इसे दुर्भाग्यपूर्ण मानता हूं कि कई भाषाओं में, जब कोई संदर्भ देता है तो यह इंगित करने के लिए कुछ भी नहीं है कि इसका उपयोग कब तक हो सकता है।
Supercat

यह निश्चित रूप से उपयोगी होगा। इसके लिए निश्चित रूप से पैटर्न हैं, लेकिन C ++ (और कई अन्य भाषाओं) में "धोखा" देना हमेशा संभव होता है।
Krumelur

एक प्रमुख तरीका जिसमें .NET जावा से बेहतर होता है वह यह है कि इसमें एक अल्पकालिक संदर्भ की अवधारणा है, लेकिन दुर्भाग्य से वस्तुओं के लिए गुणों को अल्पकालिक संदर्भों के रूप में उजागर करने का कोई तरीका नहीं है (जो मैं वास्तव में देखना चाहता हूं वह एक साधन होगा कौन सी संपत्ति का उपयोग करने वाला कोड एक कोड के लिए एक अस्थायी संदर्भ (अस्थायी चर के साथ) पारित करेगा जिसका उपयोग वस्तु का
अनुकरण

1

प्रश्न को अधिक विशिष्ट बनाने के लिए, मेरा सुझाव है कि निम्नलिखित बाधाओं का कारण यह हो सकता है कि पुस्तक के लेखक के मन में क्या हो सकता है:

  1. मान लें कि कंपाइलर एक चर के नेस्ट-नेस के संबंध में एक विशिष्ट फ़ंक्शन के व्यवहार की जांच कर रहा है। शुद्धता के लिए एक कंपाइलर को मान लेना चाहिए (क्योंकि नीचे दिए गए रूपांतर के अनुसार) यदि फ़ंक्शन को किसी अन्य फ़ंक्शन को चर कहा जाता है, तो यह धारणा # 1 केवल कोड अंशों पर लागू होती है जो फ़ंक्शन कॉल नहीं करते हैं।
  2. मान लें कि चर एक अतुल्यकालिक या समवर्ती गतिविधि द्वारा संशोधित नहीं है।
  3. मान लें कि कंपाइलर केवल यह निर्धारित कर रहा है कि चर को संशोधित किया जा सकता है, न कि यह संशोधित किया जाएगा। दूसरे शब्दों में संकलक केवल स्थैतिक विश्लेषण कर रहा है।
  4. मान लें कि कंपाइलर केवल सही ढंग से कार्य कोड पर विचार कर रहा है (सरणी ओवररन / दबाव, खराब संकेत, आदि पर विचार नहीं कर रहा है)

कंपाइलर डिज़ाइन के संदर्भ में, मुझे लगता है कि कोड जीन की शुद्धता और / या कोड ऑप्टिमाइज़ेशन के संदर्भ में 1,3,4 एक कंपाइलर लेखक की दृष्टि में सही समझ रखते हैं। अनुमान 2 अस्थिर कीवर्ड की अनुपस्थिति में समझ में आता है। और ये धारणाएँ भी प्रश्न को केंद्रित करने के लिए एक प्रस्तावित उत्तर को बहुत अधिक निश्चित करने के लिए पर्याप्त हैं :-)

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

आप तर्क दे सकते हैं कि यदि एक चर / तर्क को कास्ट चिह्नित किया जाता है, तो इसे अलियासिंग के माध्यम से बदलने के अधीन नहीं होना चाहिए, लेकिन एक संकलक लेखक के लिए जो बहुत जोखिम भरा है। किसी मानव प्रोग्रामर के लिए एक चर कांस्टेबल के हिस्से के रूप में घोषित करना जोखिम भरा हो सकता है, एक बड़ी परियोजना कहो जहां वह पूरी प्रणाली, या ओएस, या एक पुस्तकालय के व्यवहार को नहीं जानता है, वास्तव में एक जीता चर को जानने के लिए ' t बदलाव।


0

यहां तक ​​कि अगर एक चर घोषित किया जाता है const, तो इसका मतलब यह नहीं है कि कुछ बुरी तरह से लिखे गए कोड इसे ओवरराइट कर सकते हैं।

//   g++ -o foo foo.cc

#include <iostream>
void const_func(const int&a, int* b)
{
   b[0] = 2;
   b[1] = 2;
}

int main() {
   int a = 1;
   int b = 3;

   std::cout << a << std::endl;
   const_func(a,&b);
   std::cout << a << std::endl;
}

उत्पादन:

1
2

यह तब होता है क्योंकि aऔर bस्टैक चर होते हैं, और b[1]बस उसी मेमोरी स्थान के रूप में होता है a
मार्क लकाटा जूल

1
-1। अपरिभाषित व्यवहार कंपाइलर के व्यवहार पर सभी प्रतिबंधों को हटा देता है।
MSalters

डाउन वोट के बारे में अनिश्चित। यह सिर्फ एक उदाहरण है जो ओपी के मूल प्रश्न पर जाता है कि क्यों एक कंपाइलर का पता नहीं चल सकता है अगर कुछ सही मायने में constअगर सब कुछ लेबल है const। ऐसा इसलिए है क्योंकि अपरिभाषित व्यवहार C / C ++ का एक हिस्सा है। मैं रुकने की समस्या या बाहरी मानव इनपुट का उल्लेख करने के बजाय उसके प्रश्न का उत्तर देने का एक अलग तरीका खोजने की कोशिश कर रहा था।
निशान लता

0

मेरी टिप्पणियों पर विस्तार करने के लिए, उस पुस्तक का पाठ अस्पष्ट है जो इस मुद्दे को मानता है।

जैसा कि मैंने टिप्पणी की, वह पुस्तक यह कहने की कोशिश कर रही है, "चलिए हर कल्पनीय C ++ फ़ंक्शन को लिखने के लिए अनंत संख्या में बंदर मिलते हैं, जो कभी भी लिखा जा सकता है। ऐसे मामले होंगे जहां हम एक चर चुनते हैं जो (कुछ विशेष फ़ंक्शन बंदरों ने लिखा है। उपयोग करता है, हम यह काम नहीं कर सकते कि क्या फ़ंक्शन उस चर को बदल देगा। "

निश्चित रूप से किसी भी आवेदन में कुछ (यहां तक ​​कि कई) कार्यों के लिए, यह संकलक द्वारा निर्धारित किया जा सकता है, और बहुत आसानी से। लेकिन सभी के लिए (या सबसे जरूरी नहीं)।

इस फ़ंक्शन का आसानी से विश्लेषण किया जा सकता है:

static int global;

void foo()
{
}

"फू" स्पष्ट रूप से "वैश्विक" को संशोधित नहीं करता है। यह बिल्कुल भी कुछ भी संशोधित नहीं करता है, और एक संकलक इसे बहुत आसानी से काम कर सकता है।

इस फ़ंक्शन का विश्लेषण नहीं किया जा सकता है:

static int global;

int foo()
{
    if ((rand() % 100) > 50)
    {
        global = 1;
    }
    return 1;

चूंकि "फू" की क्रियाएं एक मूल्य पर निर्भर करती हैं, जो रनटाइम में बदल सकती है , इसलिए इसे संकलन समय पर निर्धारित नहीं किया जा सकता है कि क्या यह "वैश्विक" को संशोधित करेगा।

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


आप जो कहते हैं वह सच है, लेकिन यहां तक ​​कि बहुत सरल कार्यक्रमों के लिए जो सब कुछ संकलन के समय में जाना जाता है, आप कुछ भी प्रचार नहीं कर पाएंगे, ऐसा भी नहीं कि कार्यक्रम बंद हो जाएगा। यह रुकने की समस्या है। उदाहरण के लिए आप Hailstone Sequences en.wikipedia.org/wiki/Collatz_conjecture पर आधारित एक कार्यक्रम लिख सकते हैं और यदि यह एक में परिवर्तित हो जाए तो इसे सच कर दें। कंपाइलर ऐसा करने में सक्षम नहीं होंगे (क्योंकि यह कई मामलों में अतिप्रवाह होगा) और गणितज्ञ भी नहीं जानते हैं कि यह सच है या नहीं।
22

यदि आपका मतलब है " कुछ बहुत ही सरल दिखने वाले कार्यक्रम हैं जिनके लिए आप कुछ भी साबित नहीं कर सकते हैं" तो मैं पूरी तरह से सहमत हूं। लेकिन ट्यूरिंग की क्लासिक हॉल्टिंग समस्या का प्रमाण अनिवार्य रूप से एक कार्यक्रम पर निर्भर करता है, जो यह बताने में सक्षम है कि क्या यह विरोधाभास स्थापित करने के लिए रुकता है। जैसा कि यह गणित है कार्यान्वयन नहीं। निश्चित रूप से ऐसे कार्यक्रम हैं जो संकलित समय पर सांख्यिकीय रूप से निर्धारित करना पूरी तरह से संभव है कि क्या एक विशेष चर को संशोधित किया जाएगा, और क्या कार्यक्रम रुक जाएगा। यह गणितीय रूप से सिद्ध नहीं हो सकता है, लेकिन यह कुछ मामलों में व्यावहारिक रूप से प्राप्त करने योग्य है।
एल जोर्को
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.