2012-01-31 8 views
15

मेरे पास एक सूचक int* p है, और एक लूप में कुछ ऑपरेशन करें। मैं स्मृति को संशोधित नहीं करता, बस पढ़ो। यदि मैं पॉइंटर (const int* p, और int* const p) पर const जोड़ता हूं, तो क्या यह कोड को अनुकूलित करने के लिए एक कंपाइलर की सहायता कर सकता है?एक सूचक में 'कॉन्स्ट' जोड़ना अनुकूलन में मदद कर सकता है?

मुझे सुरक्षा या स्वयं-दस्तावेज जैसे const की अन्य योग्यताएं पता हैं, मैं इस विशेष मामले के बारे में पूछता हूं। प्रश्न को दोहराएं: const संकलक को किसी भी उपयोगी (अनुकूलन के लिए) जानकारी दे सकता है?

+3

क्या आपका वास्तव में 'int const * p' है? या 'int * const p'? क्या लूप? आप क्या कर रहे हैं? –

+1

आप बस इसे कर सकते हैं और जेनरेट कोड की तुलना कर सकते हैं: -? – cnicutar

+1

किसी दिए गए CPU, कंपाइलर, ओएस आदि के लिए इसे निर्धारित करने का एकमात्र तरीका यह बेंचमार्क करना है, और नतीजा केवल इस विशेष कॉन्फ़िगरेशन के लिए मान्य होगा। यह मेरे लिए समयपूर्व अनुकूलन की तरह लगता है। –

उत्तर

6

हालांकि यह कार्यान्वयन के लिए स्पष्ट रूप से विशिष्ट है, यह देखना मुश्किल है कि int* से int const* से पॉइंटर बदलने से यह कभी भी अतिरिक्त जानकारी प्रदान कर सकता है कि संकलक अन्यथा ज्ञात नहीं होता है।

दोनों मामलों में, लूप के निष्पादन के दौरान इंगित मूल्य बदल सकता है।

इसलिए यह शायद संकलक को कोड अनुकूलित करने में मदद नहीं करेगा।

+0

यह बस गलत है; 'int const *' 'const int *' के बराबर है जो * लिखने योग्य स्मृति को इंगित नहीं करता है। (आपका मतलब क्या है 'int * const') –

+1

@ जोसो: नहीं, यह सही है। वह सभी 'int const * 'इंगित करता है कि' int' उस विशेष सूचक के माध्यम से संशोधित नहीं किया जा सकता है। यदि 'int' मूल रूप से गैर-आधार था, तो इसे कोड के किसी अन्य भाग द्वारा संशोधित किया जा सकता है, या किसी कलाकार के बाद कोड के उसी भाग द्वारा संशोधित किया जा सकता है। – Mankarse

+0

मुझे आपका जवाब गलत मिला, और यह नहीं हुआ कि यह कैसे हुआ। उसके लिए खेद है। इससे भी बदतर, स्पष्ट रूप से इसे एक (नीचे) वोट को हटाने की अनुमति नहीं है जब तक कि उत्तर संपादित नहीं किया जाता है ... :( –

2

इससे मदद मिल सकती है या इससे कोई फर्क नहीं पड़ता है या इससे इसे और भी खराब हो सकता है। जानने का एकमात्र तरीका उत्सर्जित मशीन कोड दोनों का निरीक्षण करना और निरीक्षण करना है।

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

+0

क्या आपके पास कोई उदाहरण है जब यह इसे और खराब कर सकता है? –

+0

@ जकूब एम .: इस विशिष्ट मामले के लिए नहीं, लेकिन मैंने सचमुच दर्जनों मामलों को देखा है जब एक कंपाइलर इष्टतम कोड उत्सर्जित करने में असफल रहा। – sharptooth

+2

* यह इससे भी बदतर हो सकता है * एक उदाहरण के साथ प्रमाणित होने तक एक अतिस्तरीय और बहुत सामान्यीकृत कथन है, 'कॉन्स्ट' कोई फर्क नहीं पड़ता है या * कुछ * अंतर नहीं कर सकता है, और अंतर पर्याप्त रूप से नगण्य है क्योंकि इसे अनुकूलन मानदंड के रूप में उपयोग नहीं किया जाता है , इसका उपयोग केवल एक और सही रखरखाव कोड लिखने के लिए किया जाना चाहिए। –

3

नहीं। इस तरह की कॉन्स का उपयोग करने से संकलक को किसी भी जानकारी के साथ प्रदान नहीं किया जाएगा जिसका उपयोग ऑप्टिमाइज़ेशन के लिए किया जा सकता है।

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

हर्ब सटर में यह Guru of the Week कॉलम में से एक में अधिक गहराई है।

+0

यदि संकलक * उस अतिरिक्त जानकारी को साबित करने में सक्षम है, तो उसे अब 'const' योग्यता की आवश्यकता नहीं है। फिर भी 'const' अनुकूलन के साथ मदद नहीं करेगा। – Mankarse

+0

@Mankarse: जब तक कि कुछ मूर्खतापूर्ण कार्यान्वयन-विशिष्ट कारणों के लिए, उदाहरण के लिएएक विशेष अनुकूलक तब तक विश्लेषण करने से परेशान नहीं होता जब तक कि पॉइंटर कॉन्स्टेबल न हो। लेकिन आप जो भी कहते हैं उसमें आप अभी भी सही हैं, क्योंकि मेरे तर्क से * कुछ भी * अनुकूलन को प्रभावित कर सकता है - आपके चर नामों में स्वरों की संख्या, या आप टैब बनाम रिक्त स्थान के साथ इंडेंट करते हैं या नहीं। एकमात्र सवाल यह है कि यह कितना व्यावहारिक है कि अनुकूलक कुछ परिस्थितियों में कुछ संभावित रूप से उपयोगी जानकारी को अनदेखा करता है लेकिन दूसरों को नहीं। –

1

मुझे लगता है कि संकलक आपके परिदृश्य में बहुत कुछ नहीं कर सकता है। तथ्य यह है कि आपका पॉइंटर const int * const p के रूप में घोषित किया गया है यह गारंटी नहीं देता है कि स्मृति को बाहरी रूप से बदला नहीं जा सकता है, उदा। एक और धागे से। इसलिए संकलक कोड उत्पन्न करना होगा जो आपके लूप के प्रत्येक पुनरावृत्ति पर स्मृति मान को पढ़ता है।

लेकिन अगर आप स्मृति स्थान के लिए लिख सकते हैं और को आप जानते हैं कि कोड का कोई अन्य टुकड़ा, तो आप एक स्थानीय चर बना सकते हैं और यह इस के समान उपयोग कर सकते हैं नहीं जा रहे हैं:

const int * p = ... 
... 
int val = *p; 
/* use the value in a loop */ 
for (i = 0; i < BAZILLION; i++) 
{ 
    use_value(val); 
} 

न केवल आप अपने कोड के संभावित पाठकों को यह देखने के लिए मदद करते हैं कि val लूप में नहीं बदला गया है, लेकिन आप संकलक को ऑप्टिमाइज़ करने की संभावना भी देते हैं (उदाहरण के लिए val लोड करें)।

+2

कंपाइलर आमतौर पर अन्य धागे पर विचार नहीं करते हैं जब तक कि आप विशेष रूप से अस्थिर नहीं जोड़ते। हालांकि किसी भी समारोह कॉल के रास्ते में मिल जाएगा। –

+0

@PerJohansson: आप शायद सही हैं। वैसे भी, एक और धागा सिर्फ एक उदाहरण था। किसी फंक्शन कॉल का साइड इफेक्ट भी एक अच्छा उदाहरण है। मैं बस यह इंगित करना चाहता था कि संकलक द्वारा किए गए किसी भी अनुकूलन को (और करता है!) कोड के मूल अर्थशास्त्र को संरक्षित करना चाहिए, जबकि लूप के अंदर मेमोरी पढ़ने को अनुकूलित करना निश्चित रूप से नहीं होता है, और इसलिए नहीं किया जाएगा। लेकिन चूंकि 'वैल' को बाहरी रूप से (फ़ंक्शन बॉडी के बाहर) बदलने का कोई कानूनी तरीका नहीं है, इसलिए संकलक अनुकूलित करने के लिए स्वतंत्र है। –

1

const का उपयोग करना, जैसा कि हर किसी ने कहा है, संकलक को आपके लूप को अनुकूलित करने में मदद करने की संभावना नहीं है।

हालांकि, यह को लूप के बाहर या किसी कॉन्स्ट-क्वालिटी विधि के कॉल के साइट पर, या कॉन्स्ट तर्क लेने वाले फ़ंक्शन के लिए अनुकूलित करने में सहायता कर सकता है।

यह इस बात पर निर्भर करता है कि संकलक इसे अनावश्यक भार को खत्म करने, उन्हें चारों ओर स्थानांतरित करने, या गणना करने के बजाय गणना मूल्यों को कैश करने की अनुमति दे सकता है या नहीं।

यह साबित करने का एकमात्र तरीका अभी भी प्रोफ़ाइल और/या असेंबली की जांच करना है, लेकिन यही वह जगह है जहां आपको शायद दिखना चाहिए।

1

आप यह नहीं कहते कि आप किस कंपाइलर का उपयोग कर रहे हैं। लेकिन यदि आप स्मृति को पढ़ने और लिखने दोनों हैं, तो आप "प्रतिबंधित" या इसी तरह के उपयोग से लाभ उठा सकते हैं। कंपाइलर यह नहीं जानता कि क्या आपके पॉइंटर्स एक ही मेमोरी को अलियासिंग कर रहे हैं, इसलिए कोई भी स्टोर अक्सर अन्य मानों को लोड करने में मजबूर करता है। "प्रतिबंधित" संकलक को बताता है कि सूचक का कोई अलियासिंग नहीं हो रहा है और बाद के लेखन से पहले लोड किए गए मानों का उपयोग कर रख सकता है। एलियासिंग मुद्दे से बचने का एक और तरीका है स्थानीय मूल्यों में अपने मूल्यों को लोड करना, फिर संकलक को लिखने के बाद पुनः लोड करने के लिए मजबूर नहीं किया जाता है।