बेहतर प्रदर्शन पाने के लिए एम्बेडेड सॉफ़्टवेयर के लिए फ़ंक्शन लिखते समय सबसे अच्छा तरीका क्या है? [बन्द है]


13

मैंने कुछ पुस्तकालयों को माइक्रोकंट्रोलर्स के लिए देखा है और उनके कार्य एक समय में एक काम करते हैं। उदाहरण के लिए, कुछ इस तरह:

void setCLK()
{
    // Code to set the clock
}

void setConfig()
{
    // Code to set the config
}

void setSomethingElse()
{
   // 1 line code to write something to a register.
}

फिर इसके शीर्ष पर अन्य कार्य आते हैं जो इस 1 लाइन कोड का उपयोग करता है जिसमें अन्य उद्देश्यों की सेवा करने के लिए फ़ंक्शन होता है। उदाहरण के लिए:

void initModule()
{
   setCLK();
   setConfig();
   setSomethingElse();
}

मुझे यकीन नहीं है, लेकिन मेरा मानना ​​है कि इस तरह से जंप के लिए अधिक कॉल करना और हर बार किसी फ़ंक्शन को कॉल करने या बाहर निकलने पर रिटर्न एड्रेस को स्टैक करने के ओवरहेड बनाना होगा। और यह कार्यक्रम को धीमा काम करेगा, है ना?

मैंने खोज की है और हर जगह वे कहते हैं कि प्रोग्रामिंग का नियम यह है कि एक फ़ंक्शन को केवल एक कार्य करना चाहिए।

इसलिए अगर मैं सीधे एक InitModule फ़ंक्शन मॉड्यूल लिखता हूं जो घड़ी सेट करता है, कुछ वांछित कॉन्फ़िगरेशन जोड़ता है और कॉलिंग फ़ंक्शन के बिना कुछ और करता है। एम्बेडेड सॉफ्टवेयर लिखते समय क्या यह एक बुरा दृष्टिकोण है?


संपादित करें 2:

  1. ऐसा लगता है कि बहुत से लोग इस सवाल को समझ गए हैं जैसे कि मैं एक कार्यक्रम को अनुकूलित करने की कोशिश कर रहा हूं। नहीं, मेरा कोई इरादा नहीं है । मैं संकलक को ऐसा करने दे रहा हूं, क्योंकि यह हमेशा होने वाला है (मुझे आशा है कि हालांकि!) मुझसे बेहतर नहीं है।

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

कृपया @ जोंक के उत्तर में परिभाषित पठनीयता पर विचार करें ।


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

10
@akohlsmith IIRC अनुकूलन के तीन नियम हैं: 1) नहीं! 2) नहीं सच में नहीं! 3) पहले प्रोफाइल, फिर और उसके बाद ही ऑप्टिमाइज़ करें अगर आपको चाहिए - Michael_A._Jackson
esoterik

3
बस याद रखें कि "समयपूर्व अनुकूलन प्रोग्रामिंग में सभी बुराई (या कम से कम सबसे अधिक) की जड़ है" - नुथ
मावग का कहना है कि मोनिका

1
@Mawg: ऑपरेटिव शब्द समय से पहले है । (जैसा कि उस पेपर में अगला पैराग्राफ बताता है। सचमुच अगला वाक्य है: "फिर भी हमें उस महत्वपूर्ण 3% में अपने अवसरों को पास नहीं करना चाहिए।") आप जिस विकल्प की आवश्यकता है उसे टिल न करें - आपको धीमी गति से नहीं मिलेगा। बिट्स टिल आपके पास प्रोफाइल के लिए कुछ है - लेकिन यह भी निराशावाद में संलग्न नहीं है, उदाहरण के लिए नौकरी के लिए गलत तरीके से गलत टूल का उपयोग करके।
cHao

1
@Mawg मुझे नहीं पता कि मुझे अनुकूलन से संबंधित उत्तर / प्रतिक्रिया क्यों मिली, क्योंकि मैंने कभी भी शब्द का उल्लेख नहीं किया है और मैं इसे करने का इरादा रखता हूं। सवाल यह है कि बेहतर प्रदर्शन प्राप्त करने के लिए एंबेडेड प्रोग्रामिंग में कार्यों को कैसे लिखा जाए।
MaNyYaCk

जवाबों:


28

यकीनन, आपके उदाहरण में प्रदर्शन कोई मायने नहीं रखेगा, क्योंकि कोड केवल एक बार स्टार्टअप पर चलाया जाता है।

अंगूठे का एक नियम जो मैं उपयोग करता हूं: अपने कोड को जितना संभव हो उतना पठनीय लिखें और केवल यह अनुकूलन करना शुरू करें कि आप नोटिस करते हैं कि आपका कंपाइलर ठीक से अपना जादू नहीं कर रहा है।

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

इसके अलावा, जैसा कि पहले ही दूसरों द्वारा देखा गया है, फंक्शन कॉल की लागत (और अर्थ 'लागत) प्लेटफॉर्म, कंपाइलर, कंपाइलर ऑप्टिमाइज़ेशन सेटिंग और एप्लिकेशन की आवश्यकताओं के अनुसार भिन्न होती है। 8051 और कॉर्टेक्स-एम 7, और पेसमेकर और लाइट स्विच के बीच बहुत अंतर होगा।


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

11

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

जो हमें लब्बोलुआब में लाता है। आपका व्यापक प्रश्न क्षेत्र दशकों से, कुछ बहस का विषय रहा है और आज भी कुछ बहस का विषय बना हुआ है। इसलिए, कम से कम जैसा कि मैंने आपके प्रश्न को पढ़ा है, यह मुझे एक राय-आधारित प्रश्न प्रतीत होता है (जैसा आपने पूछा था।)

इसे राय-आधारित होने से दूर ले जाया जा सकता है, क्योंकि यदि आप स्थिति के बारे में अधिक विस्तृत होना चाहते हैं और ध्यान से वर्णित उद्देश्यों को प्राथमिक मानते हैं। जितना बेहतर आप अपने माप उपकरणों को परिभाषित करेंगे, उतने अधिक उद्देश्य उत्तर हो सकते हैं।


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

  1. अपने दृष्टिकोण के बारे में लगातार रहें, ताकि आपके कोड को पढ़ने वाला एक समझ विकसित कर सके कि आप अपनी कोडिंग प्रक्रिया के बारे में क्या सोचते हैं। असंगत होना शायद सबसे बुरा संभव अपराध है। यह न केवल दूसरों के लिए मुश्किल बनाता है, बल्कि खुद के लिए कोड वर्षों बाद वापस आना मुश्किल बनाता है।
  2. डिग्री के लिए संभव है, चीजों को आज़माएं और व्यवस्थित करें ताकि ऑर्डर देने के संबंध में विभिन्न कार्यात्मक वर्गों का आरंभ किया जा सके। जहां ऑर्डर करने की आवश्यकता होती है, अगर यह दो उच्च संबंधित उप-युग्मों के करीबी युग्मन के कारण है , तो दोनों के लिए एक एकल आरंभीकरण पर विचार करें ताकि इसे नुकसान पहुंचाए बिना फिर से व्यवस्थित किया जा सके। यदि यह संभव नहीं है, तो आरम्भिकरण आदेश की आवश्यकता का दस्तावेजीकरण करें।
  3. Encapsulate ज्ञान वास्तव में एक ही स्थान पर, यदि संभव हो तो। लगातार कोड में सभी जगह नकल नहीं की जानी चाहिए। कुछ चर के लिए हल करने वाले समीकरण एक और एक ही स्थान पर मौजूद होने चाहिए। और इसी तरह। यदि आप अपने आप को लाइनों के कुछ सेट को कॉपी और पेस्ट करते हुए पाते हैं, जो विभिन्न स्थानों पर कुछ आवश्यक व्यवहार करते हैं, तो उस ज्ञान को एक स्थान पर कब्जा करने और जहां जरूरत हो, वहां उपयोग करने के तरीके पर विचार करें। उदाहरण के लिए, यदि आपके पास एक पेड़ की संरचना है जिसे एक विशिष्ट तरीके से चलना चाहिए, तो नहींप्रत्येक स्थान पर ट्री-वॉकिंग कोड को दोहराएं जहां आपको ट्री नोड्स के माध्यम से लूप की आवश्यकता होती है। इसके बजाय, ट्री-वॉकिंग विधि को एक स्थान पर कैप्चर करें और इसका उपयोग करें। इस तरह, अगर पेड़ बदल जाता है और चलने का तरीका बदल जाता है, तो आपके पास चिंता करने के लिए केवल एक ही जगह होती है और बाकी सभी कोड "बस सही काम करते हैं।"
  4. यदि आप कागज के एक विशाल, समतल शीट पर अपने सभी रूटीन फैलाते हैं, तो उन्हें अन्य रूटीन के रूप में जोड़ने वाले तीरों के साथ, आप किसी भी एप्लिकेशन में देखेंगे कि रूटीन के "क्लस्टर" होंगे जिनमें बहुत सारे और बहुत सारे तीर हैं खुद के बीच लेकिन समूह के बाहर केवल कुछ तीर। इसलिए निकट युग्मित दिनचर्या के अन्य समूहों के बीच घनिष्ठ युग्मित दिनचर्या और शिथिल युग्मित संबंध की प्राकृतिक सीमाएं होंगी । अपने कोड को मॉड्यूल में व्यवस्थित करने के लिए इस तथ्य का उपयोग करें। यह आपके कोड की स्पष्ट जटिलता को काफी हद तक सीमित कर देगा।

उपरोक्त सभी कोडिंग के बारे में आम तौर पर सही है। मैंने मापदंडों, स्थानीय या स्थिर वैश्विक चर आदि के उपयोग पर चर्चा नहीं की। इसका कारण यह है कि एम्बेडेड प्रोग्रामिंग के लिए अनुप्रयोग स्थान अक्सर चरम और बहुत महत्वपूर्ण नए अवरोधों को रखता है और हर एम्बेडेड अनुप्रयोग पर चर्चा किए बिना उन सभी पर चर्चा करना असंभव है। और यहाँ वैसे भी नहीं हो रहा है।

ये बाधाएँ इनमें से कोई भी (और अधिक) हो सकती हैं:

  • गंभीर लागत सीमाएँ जो न्यूनतम आदिम MCUs रैम और लगभग कोई I / O पिन-काउंट के साथ की आवश्यकता होती हैं। इनके लिए, नियमों के पूरे नए सेट लागू होते हैं। उदाहरण के लिए, आपको असेंबली कोड में लिखना पड़ सकता है क्योंकि बहुत अधिक कोड स्थान नहीं है। आपको केवल स्थैतिक चर का उपयोग करना पड़ सकता है क्योंकि स्थानीय चर का उपयोग बहुत महंगा और समय लेने वाला है। आपको सबरूटीन्स के अत्यधिक उपयोग से बचना पड़ सकता है क्योंकि (उदाहरण के लिए, कुछ माइक्रोचिप पीआईसी पार्ट्स) केवल 4 हार्डवेयर रजिस्टर हैं जिसमें सबरूटीन रिटर्न एड्रेस स्टोर करना है। तो आपको अपने कोड को नाटकीय रूप से "समतल" करना पड़ सकता है। आदि।
  • गंभीर विद्युत सीमाएँ जिन्हें ध्यान से तैयार किए गए कोड की आवश्यकता होती है, पूर्ण गति से चलने पर MCU के अधिकांश भाग को बंद करने और कोड के निष्पादन समय पर गंभीर सीमाएँ बंद करने की आवश्यकता होती है। फिर, इसके लिए कुछ असेंबली कोडिंग की आवश्यकता हो सकती है।
  • गंभीर समय की आवश्यकताएं। उदाहरण के लिए, ऐसे समय होते हैं जहाँ मुझे यह सुनिश्चित करना होता है कि एक ओपन-ड्रेन 0 के प्रसारण को ठीक उसी तरह से कई चक्रों में ले जाना पड़े जैसे कि 1. एक का संचरण इस समय के लिए एक सटीक रिश्तेदार चरण के साथ। इसका मतलब था कि C का यहाँ उपयोग नहीं किया जा सकता है। उस गारंटी को बनाने का एकमात्र संभव तरीका विधानसभा कोड को सावधानीपूर्वक बनाना है। (और फिर भी, हमेशा सभी ALU डिजाइनों पर नहीं।)

और इसी तरह। (लाइफ-क्रिटिकल मेडिकल इंस्ट्रूमेंटेशन के लिए वायरिंग कोड की अपनी पूरी दुनिया होती है, साथ ही।)

यहाँ पर मुख्य बात यह है कि एम्बेडेड कोडिंग अक्सर कुछ फ्री-फॉर-ऑल नहीं होती है, जहाँ आप कोड कर सकते हैं जैसे आप वर्कस्टेशन पर कर सकते हैं। अक्सर बहुत कठिन बाधाओं की एक विस्तृत विविधता के लिए गंभीर, प्रतिस्पर्धी कारण होते हैं। और ये अधिक पारंपरिक और स्टॉक उत्तरों के खिलाफ दृढ़ता से बहस कर सकते हैं ।


पठनीयता के बारे में, मुझे लगता है कि यह कोड पठनीय है यदि यह एक सुसंगत फैशन में लिखा गया है जो मैं इसे पढ़ सकता हूं। और जहां कोड को बाधित करने का जानबूझकर प्रयास नहीं किया गया है। वास्तव में बहुत अधिक आवश्यक नहीं है।

पठनीय कोड काफी कुशल हो सकता है और यह उपरोक्त सभी आवश्यकताओं को पूरा कर सकता है जो मैंने पहले ही उल्लेख किया है। मुख्य बात यह है कि आप पूरी तरह से समझते हैं कि आपके द्वारा लिखी गई कोड की प्रत्येक पंक्ति असेंबली या मशीन के स्तर पर क्या पैदा करती है। सी ++ प्रोग्रामर पर एक गंभीर बोझ डालता है क्योंकि कई परिस्थितियां हैं जहां सी ++ कोड के समान स्निपेट वास्तव में मशीन कोड के अलग-अलग स्निपेट उत्पन्न करते हैं जिनमें काफी अलग-अलग प्रदर्शन होते हैं। लेकिन सी, आम तौर पर, ज्यादातर एक "आप जो देखते हैं वह है जो आपको मिलता है" भाषा। तो यह उस संबंध में सुरक्षित है।


जेसन प्रति EDIT:

मैं 1978 से C का उपयोग कर रहा हूं और 1987 के बाद से C ++ और मुझे दोनों मेनफ्रेम, मिनीकंप्यूटर और (ज्यादातर) एम्बेडेड अनुप्रयोगों के लिए दोनों का उपयोग करने का बहुत अनुभव है।

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

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

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

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

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


सी ++

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

  • आंशिक टेम्पलेट विशेषज्ञता
  • vtables
  • आभासी आधार वस्तु
  • सक्रियण फ्रेम
  • सक्रियण फ्रेम खोलना
  • बिल्डरों में स्मार्ट पॉइंटर्स का उपयोग, और क्यों
  • वापसी मूल्य अनुकूलन

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

चलो बस एक स्वाद पाने के लिए C ++ अपवाद शब्दार्थ पर एक नज़र डालें।

C ++ कंपाइलर को कंपाइलिंग यूनिट के लिए सही कोड जनरेट करना होगा, जब यह पूरी तरह से पता नहीं है कि अलग-अलग और अलग-अलग समय पर संकलित किए गए अलग- अलग संकलन में किस तरह के अपवाद हैंडलिंग की आवश्यकता हो सकती है । AB

कुछ संकलन इकाई में कुछ फ़ंक्शन के भाग के रूप में पाया गया कोड का यह क्रम लें :A

   .
   .
   foo ();
   String s;
   foo ();
   .
   .

चर्चा के उद्देश्यों के लिए, संकलन इकाई अपने स्रोत में कहीं भी 'try..catch' का उपयोग नहीं करता है । न ही यह 'थ्रो' का उपयोग करता है। वास्तव में, मान लें कि यह किसी भी स्रोत का उपयोग नहीं करता है जिसे सी कंपाइलर द्वारा संकलित नहीं किया जा सकता है, इस तथ्य के अलावा कि यह सी ++ लाइब्रेरी समर्थन का उपयोग करता है और स्ट्रिंग जैसी वस्तुओं को संभाल सकता है। यह कोड सी स्रोत कोड फ़ाइल भी हो सकती है जिसे कुछ सी ++ सुविधाओं का लाभ लेने के लिए थोड़ा संशोधित किया गया था, जैसे स्ट्रिंग क्लास।A

इसके अलावा, मान लें कि फू () संकलन इकाई में स्थित एक बाहरी प्रक्रिया है और संकलक के पास इसके लिए एक घोषणा है, लेकिन इसकी परिभाषा नहीं जानता है।B

C ++ कंपाइलर foo () के लिए पहली कॉल देखता है और अगर कोई अपवाद फेंकता है, तो केवल एक सामान्य सक्रियण फ़्रेम को होने की अनुमति दे सकता है। दूसरे शब्दों में, C ++ कंपाइलर जानता है कि अपवाद हैंडलिंग में शामिल फ्रेम खोल प्रक्रिया का समर्थन करने के लिए इस बिंदु पर किसी अतिरिक्त कोड की आवश्यकता नहीं है।

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

( इस समस्या को सीमित करने में सहायता के लिए C ++ में अतिरिक्त सजावट जोड़ना संभव है। लेकिन तथ्य यह है कि, C ++ का उपयोग करने वाले प्रोग्रामर को कोड लिखने की प्रत्येक पंक्ति के निहितार्थों के बारे में अधिक जानकारी होनी चाहिए।)

C के मॉलोक के विपरीत, C ++ के नए अपवादों को संकेत करने के लिए उपयोग करता है जब यह कच्चे मेमोरी आवंटन नहीं कर सकता है। तो 'डायनामिक_कास्ट' होगा। (देखें स्ट्रॉस्ट्रुप का तीसरा संस्करण। C ++ प्रोग्रामिंग लैंग्वेज, पृष्ठ 384 और 385 C C ++ में मानक को छोड़कर।) कंपाइलर इस व्यवहार को अक्षम कर सकते हैं। लेकिन सामान्य तौर पर आप जनरेट किए गए कोड में प्रोलेग और एपिलॉग को ठीक से बनाए गए अपवाद के कारण कुछ ओवरहेड को उकसाएंगे, तब भी जब अपवाद वास्तव में जगह नहीं लेते हैं और तब भी जब फ़ंक्शन संकलित किया जा रहा है, वास्तव में कोई अपवाद हैंडलिंग ब्लॉक नहीं है। (स्ट्रॉस्ट्रुप ने सार्वजनिक रूप से इस पर अफसोस जताया है।)

आंशिक टेम्पलेट विशेषज्ञता के बिना (सभी C ++ कंपाइलर इसका समर्थन नहीं करते हैं), टेम्पलेट्स का उपयोग एम्बेडेड प्रोग्रामिंग के लिए आपदा जादू कर सकता है। इसके बिना, कोड ब्लूम एक गंभीर जोखिम है जो एक फ्लैश में एक छोटे-मेमोरी एम्बेडेड प्रोजेक्ट को मार सकता है।

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

एक एकल पैरामीटर प्रकार के साथ एक ऑब्जेक्ट कंस्ट्रक्टर प्रदान करने से प्रोग्रामर को पूरी तरह से अनपेक्षित तरीके से दो प्रकारों के बीच रूपांतरण पथ खोजने के लिए C ++ कंपाइलर की अनुमति मिल सकती है। इस तरह का "स्मार्ट" व्यवहार सी का हिस्सा नहीं है।

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

C ++ कंपाइलर आपके लिए अनपेक्षित परिणामों के साथ स्वचालित रूप से आपके लिए कंस्ट्रक्टर, डिस्ट्रक्टर्स, कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटर उत्पन्न कर सकते हैं। इसके विवरण के साथ सुविधा प्राप्त करने में समय लगता है।

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

चूंकि C ++ आंशिक रूप से निर्मित वस्तुओं के विध्वंसक का आह्वान नहीं करता है जब ऑब्जेक्ट कंस्ट्रक्टर में कोई अपवाद होता है, तो कंस्ट्रक्टर में अपवादों को संभालने के लिए आमतौर पर "स्मार्ट पॉइंटर्स" को अनिवार्य किया जाता है ताकि यह सुनिश्चित किया जा सके कि यदि कोई अपवाद होता है, तो कंस्ट्रक्टर में निर्मित टुकड़े ठीक से नष्ट हो जाते हैं। । (देखें स्ट्रॉस्ट्रप, पृष्ठ 367 और 368।) सी ++ में अच्छी कक्षाएं लिखने में यह एक सामान्य मुद्दा है, लेकिन निश्चित रूप से सी में टाला गया क्योंकि सी में निर्माण और विनाश के शब्दार्थ नहीं हैं। निर्माण को संभालने के लिए उचित कोड लिखना। किसी वस्तु के भीतर उप-विषय का मतलब कोड लिखना जो C ++ में इस अनूठे शब्दार्थ मुद्दे से सामना करना चाहिए; दूसरे शब्दों में "सी + + अर्थ व्यवहार के आसपास लेखन"।

C ++ ऑब्जेक्ट्स को ऑब्जेक्ट पैरामीटर में पारित कर सकता है। उदाहरण के लिए, निम्नलिखित अंशों में, कॉल "आरए (एक्स);" C ++ कंपाइलर को पैरामीटर p के लिए एक कंस्ट्रक्टर को लागू करने के लिए कारण हो सकता है, तब ऑब्जेक्ट एक्स को पैरामीटर p में स्थानांतरित करने के लिए कॉपी कंस्ट्रक्टर को कॉल करें, फिर रिटर्न ऑब्जेक्ट के लिए एक अन्य कंस्ट्रक्टर (फ़ंक्शन का एक अनाम अस्थायी) rA, जो निश्चित रूप से पैरामीटर p से कॉपी किया गया। इससे भी बदतर, अगर क्लास ए की अपनी वस्तुएं हैं जिन्हें निर्माण की आवश्यकता है, तो यह आपदा को दूरबीन कर सकता है। (एसी प्रोग्रामर इस कचरे से सबसे अधिक बचेंगे, हाथ अनुकूलन के बाद से सी प्रोग्रामर के पास इतना आसान सिंटैक्स नहीं है और एक बार में सभी विवरणों को व्यक्त करना होगा।)

    class A {...};
    A rA (A p) { return p; }
    // .....
    { A x; rA(x); }

अंत में, सी प्रोग्रामर के लिए एक छोटा नोट। longjmp () के पास C ++ में पोर्टेबल व्यवहार नहीं है। (कुछ C प्रोग्रामर इसे एक तरह के "अपवाद" तंत्र के रूप में उपयोग करते हैं।) कुछ C ++ कंपाइलर वास्तव में लॉन्गजंप लेने पर चीजों को साफ करने के लिए सेट करने का प्रयास करेंगे, लेकिन C ++ में वह व्यवहार पोर्टेबल नहीं है। यदि कंपाइलर निर्मित वस्तुओं को साफ करता है, तो यह गैर-पोर्टेबल है। यदि कंपाइलर उन्हें साफ नहीं करता है, तो ऑब्जेक्ट तबाह नहीं होते हैं जब कोड longjmp के परिणामस्वरूप कोड की गई वस्तुओं के दायरे को छोड़ देता है और व्यवहार अमान्य है। (अगर foo में longjmp का उपयोग) एक गुंजाइश नहीं छोड़ता है, तो व्यवहार ठीक हो सकता है।) यह अक्सर सी एम्बेडेड प्रोग्रामर द्वारा उपयोग नहीं किया जाता है, लेकिन उन्हें उपयोग करने से पहले इन मुद्दों से खुद को अवगत कराना चाहिए।


4
केवल एक बार उपयोग किए जाने वाले इस प्रकार के फ़ंक्शन को फ़ंक्शन कॉल के रूप में कभी भी संकलित नहीं किया जाता है, कोड को बस वहां बिना किसी कॉल के रखा जाता है।
डोरियन

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

1
@ जोंक - एक अन्य चाल जिसे आपने एक अच्छे उत्तर में उल्लेख नहीं किया है, वह सरल मैक्रो फ़ंक्शंस लिखना है जो विस्तारित इनलाइन कोड के रूप में प्रारंभिक या कॉन्फ़िगरेशन का प्रदर्शन करता है। यह विशेष रूप से बहुत छोटे प्रोसेसर पर उपयोगी है जहां रैम / स्टैक / फ़ंक्शन कॉल की गहराई सीमित है।
uɐɪ

@ rosou in हाँ, मैं सी। में मैक्रोज़ पर चर्चा करने से चूक गया। वे सी ++ में पदावनत हैं, लेकिन उस बिंदु पर चर्चा उपयोगी हो सकती है। मैं इसे संबोधित कर सकता हूं, अगर मैं इसके बारे में लिखने के लिए कुछ उपयोगी समझ सकता हूं।
जोंक १६'१ 'को .:

1
@ जोंक - मैं आपके पहले वाक्य से पूरी तरह असहमत हूं। एक उदाहरण inline static void turnOnFan(void) { PORTAbits &= ~(1<<8); }जो कई स्थानों पर कहा जाता है, एक आदर्श उम्मीदवार है।
जेसन एस

8

1) पहले पठनीयता और स्थिरता के लिए कोड। किसी भी कोडबेस का सबसे महत्वपूर्ण पहलू यह है कि यह अच्छी तरह से संरचित है। कम लिखित सॉफ़्टवेयर में कम त्रुटियां होती हैं। आपको कुछ हफ़्ते / महीनों / वर्षों में बदलाव करने की आवश्यकता हो सकती है, और यदि आपका कोड पढ़ने में अच्छा लगे तो यह बहुत मदद करता है। या हो सकता है किसी और को बदलाव करना पड़े।

2) एक बार चलने वाले कोड का प्रदर्शन बहुत ज्यादा मायने नहीं रखता है। शैली के लिए देखभाल, प्रदर्शन के लिए नहीं

3) तंग छोरों में भी कोड पहले और सबसे महत्वपूर्ण सही होने की जरूरत है। यदि आप प्रदर्शन समस्याओं का सामना करते हैं, तो कोड सही होने के बाद अनुकूलित करें।

4) यदि आपको अनुकूलन करने की आवश्यकता है, तो आपको मापना होगा! इससे कोई फर्क नहीं पड़ता कि आप सोचते हैं या कोई आपको बताता है कि static inlineसंकलक के लिए सिर्फ एक सिफारिश है। आपको यह देखना होगा कि कंपाइलर क्या करता है। आपको यह भी मापना होगा कि इनलाइनिंग ने प्रदर्शन में सुधार किया है या नहीं। एम्बेडेड सिस्टम में, आपको कोड आकार भी मापना होगा, क्योंकि कोड मेमोरी आमतौर पर बहुत सीमित होती है। यह सबसे महत्वपूर्ण नियम है जो इंजीनियरिंग को अनुमान से अलग करता है। यदि आप इसे नहीं मापते हैं, तो यह मदद नहीं करता है। इंजीनियरिंग नाप रहा है। विज्ञान इसे लिख रहा है;)


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

2
आरंभीकरण कोड का प्रदर्शन पहले अप्रासंगिक हो सकता है। जब आप कम-पावर मोड जोड़ते हैं, और वेकअप इवेंट को संभालने के लिए जल्दी से ठीक होना चाहते हैं, तो यह प्रासंगिक हो जाता है।
बेरेन्डी - विरोध 4

5

जब किसी फ़ंक्शन को केवल एक स्थान पर (यहां तक ​​कि अन्य फ़ंक्शन के अंदर भी) कॉल किया जाता है, तो कंपाइलर ऑलवेज उस फ़ंक्शन को वास्तव में कॉल करने के बजाय उस स्थान पर कोड डालता है। यदि फ़ंक्शन को कई स्थानों पर कहा जाता है, तो यह कम से कम कोड आकार के दृष्टिकोण से फ़ंक्शन का उपयोग करने के लिए समझ में आता है।

कोड संकलित करने के बाद कई कॉल नहीं होंगे इसके बजाय पठनीयता में बहुत सुधार होगा।

इसके अलावा आप उदाहरण के लिए एडीसी इनिट कोड के साथ उसी एडीसी फ़ंक्शन के साथ अन्य सी सी फ़ंक्शंस में मुख्य सी फ़ाइल में नहीं होना चाहेंगे।

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

गति के लिए ऑप्टिमाइज़ेशन कई स्थानों पर इनलाइन फ़ंक्शन करेगा, कोड आकार के लिए ऑप्टिमाइज़ेशन फ़ंक्शन को कॉल करेगा, हालांकि, जब कोई फ़ंक्शन केवल एक ही स्थान पर कॉल किया जाता है जैसा कि आपके मामले में यह हमेशा "इनबिल्ड" होगा।

इस तरह कोड:

function_used_just_once{
   code blah blah;
}
main{
  codeblah;
  function_used_just_once();
  code blah blah blah;
{

इसके लिए संकलन करेंगे:

main{
 code blah;
 code blah blah;
 code blah blah blah;
}

किसी भी कॉल का उपयोग किए बिना।

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

यह निर्दिष्ट करने के लिए अपडेट करें कि उपरोक्त कथन माइक्रोचिप XCxx मुक्त संस्करण जैसे उद्देश्य से अपंग मुक्त संस्करण संकलक के लिए मान्य नहीं हैं। इस तरह के फंक्शन कॉल्स माइक्रोचिप के लिए एक सोने की खदान है, यह दिखाने के लिए कि भुगतान किया गया संस्करण कितना बेहतर है और यदि आप इसे संकलित करते हैं, तो आप ASM में ठीक उसी तरह पाएंगे, जैसे कि आपके पास C कोड में है।

इसके अलावा यह गूंगे प्रोग्रामर के लिए नहीं है जो एक इनबिल्ड फ़ंक्शन में पॉइंटर का उपयोग करने की उम्मीद करते हैं।

यह इलेक्ट्रॉनिक्स सेक्शन है, सामान्य C C ++ या प्रोग्रामिंग सेक्शन नहीं है, यह सवाल माइक्रोकंट्रोलर प्रोग्रामिंग के बारे में है जहाँ कोई भी सभ्य संकलक डिफ़ॉल्ट रूप से उपरोक्त अनुकूलन करेगा।

तो कृपया नीचे ही रोकें क्योंकि दुर्लभ, असामान्य मामलों में यह सच नहीं हो सकता है।


15
क्या कोड इनलाइन हो जाता है या नहीं एक कंपाइलर विक्रेता कार्यान्वयन विशिष्ट मुद्दा है; इनलाइन कीवर्ड का उपयोग करते हुए भी इनलाइन कोड की गारंटी नहीं देता है । यह संकलक को संकेत है। निश्चित रूप से अच्छे संकलक इनलाइन कार्यों का उपयोग केवल एक बार करेंगे यदि वे उनके बारे में जानते हैं। यह आम तौर पर ऐसा नहीं करेगा यदि गुंजाइश में कोई "अस्थिर" वस्तुएं हैं, हालांकि।
पीटर स्मिथ

9
यह जवाब सिर्फ सच नहीं है। जैसा कि @PeterSmith कहता है, और सी भाषा विनिर्देश के अनुसार, कंपाइलर में कोड को इनलाइन करने का विकल्प होता है, लेकिन हो सकता है और कई मामलों में ऐसा नहीं होगा। इतने अलग-अलग टार्गेट प्रोसेसर के लिए दुनिया में बहुत सारे अलग-अलग कंपाइलर हैं जो इस उत्तर में कंबल स्टेटमेंट बनाते हैं और यह मानते हुए कि सभी कंपाइलर कोड इनलाइन डालेंगे, जब उनके पास केवल विकल्प ही नहीं होगा।
u

2
@ isou not आप ऐसे दुर्लभ मामलों की ओर संकेत कर रहे हैं, जहां संभव नहीं है और पहली जगह में किसी समारोह को नहीं कहना एक बुरा विचार होगा। मैंने ओपी द्वारा दिए गए सरल उदाहरण में वास्तव में कॉल का उपयोग करने के लिए एक कंपाइलर कभी नहीं देखा है।
डोरियन

6
ऐसे मामलों में जहां इन कार्यों को केवल एक बार कहा जाता है, फ़ंक्शन कॉल को अनुकूलित करना बहुत गैर-मुद्दा है। क्या सिस्टम को वास्तव में सेटअप के दौरान हर एक घड़ी चक्र को वापस करने की आवश्यकता है? जैसा कि कहीं भी अनुकूलन के साथ होता है - पठनीय कोड लिखें, और केवल तभी ऑप्टिमाइज़ करें जब प्रोफाइल दिखाता है कि इसकी आवश्यकता है
बाल्ड्रिक

5
@ मायर्स मैं इस बात से चिंतित नहीं हूं कि कंपाइलर यहां क्या कर रहा है - प्रोग्रामर के पास यह कैसे पहुंचता है। वहाँ या तो कोई है, या नगण्य प्रदर्शन हिट प्रैस को तोड़ने से मारा गया है जैसा कि प्रश्न में देखा गया है।
बाल्ड्रिक

2

सबसे पहले, कोई सबसे अच्छा या सबसे खराब नहीं है; यह सब राय का विषय है। आप बहुत सही हैं कि यह अक्षम है। इसे बाहर अनुकूलित किया जा सकता है या नहीं; निर्भर करता है। आमतौर पर आप इस प्रकार के फ़ंक्शन, घड़ी, GPIO, टाइमर, आदि को अलग-अलग फ़ाइलों / निर्देशिकाओं में देखेंगे। कंपाइलर आमतौर पर इन अंतरालों के दौरान अनुकूलन नहीं कर पाए हैं। एक ऐसा है जो मुझे पता है, लेकिन इस तरह से सामान के लिए व्यापक रूप से उपयोग नहीं किया जा सकता है।

एक दस्तावेज:

void dummy (unsigned int);

void setCLK()
{
    // Code to set the clock
    dummy(5);
}

void setConfig()
{
    // Code to set the configuration
    dummy(6);
}

void setSomethingElse()
{
   // 1 line code to write something to a register.
    dummy(7);
}

void initModule()
{
   setCLK();
   setConfig();
   setSomethingElse();
}

प्रदर्शन उद्देश्यों के लिए एक लक्ष्य और संकलक चुनना।

Disassembly of section .text:

00000000 <setCLK>:
   0:    e92d4010     push    {r4, lr}
   4:    e3a00005     mov    r0, #5
   8:    ebfffffe     bl    0 <dummy>
   c:    e8bd4010     pop    {r4, lr}
  10:    e12fff1e     bx    lr

00000014 <setConfig>:
  14:    e92d4010     push    {r4, lr}
  18:    e3a00006     mov    r0, #6
  1c:    ebfffffe     bl    0 <dummy>
  20:    e8bd4010     pop    {r4, lr}
  24:    e12fff1e     bx    lr

00000028 <setSomethingElse>:
  28:    e92d4010     push    {r4, lr}
  2c:    e3a00007     mov    r0, #7
  30:    ebfffffe     bl    0 <dummy>
  34:    e8bd4010     pop    {r4, lr}
  38:    e12fff1e     bx    lr

0000003c <initModule>:
  3c:    e92d4010     push    {r4, lr}
  40:    e3a00005     mov    r0, #5
  44:    ebfffffe     bl    0 <dummy>
  48:    e3a00006     mov    r0, #6
  4c:    ebfffffe     bl    0 <dummy>
  50:    e3a00007     mov    r0, #7
  54:    ebfffffe     bl    0 <dummy>
  58:    e8bd4010     pop    {r4, lr}
  5c:    e12fff1e     bx    lr

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

void dummy (unsigned int);

static void setCLK()
{
    // Code to set the clock
    dummy(5);
}

static void setConfig()
{
    // Code to set the configuration
    dummy(6);
}

static void setSomethingElse()
{
   // 1 line code to write something to a register.
    dummy(7);
}

void initModule()
{
   setCLK();
   setConfig();
   setSomethingElse();
}

उन्हें हटा दिया जाता है क्योंकि वे अंतर्निर्मित हैं।

Disassembly of section .text:

00000000 <initModule>:
   0:    e92d4010     push    {r4, lr}
   4:    e3a00005     mov    r0, #5
   8:    ebfffffe     bl    0 <dummy>
   c:    e3a00006     mov    r0, #6
  10:    ebfffffe     bl    0 <dummy>
  14:    e3a00007     mov    r0, #7
  18:    ebfffffe     bl    0 <dummy>
  1c:    e8bd4010     pop    {r4, lr}
  20:    e12fff1e     bx    lr

लेकिन वास्तविकता यह है कि जब आप चिप विक्रेता या बीएसपी पुस्तकालयों को लेते हैं,

Disassembly of section .text:

00000000 <_start>:
   0:    e3a0d902     mov    sp, #32768    ; 0x8000
   4:    eb000010     bl    4c <initModule>
   8:    eafffffe     b    8 <_start+0x8>

0000000c <dummy>:
   c:    e12fff1e     bx    lr

00000010 <setCLK>:
  10:    e92d4010     push    {r4, lr}
  14:    e3a00005     mov    r0, #5
  18:    ebfffffb     bl    c <dummy>
  1c:    e8bd4010     pop    {r4, lr}
  20:    e12fff1e     bx    lr

00000024 <setConfig>:
  24:    e92d4010     push    {r4, lr}
  28:    e3a00006     mov    r0, #6
  2c:    ebfffff6     bl    c <dummy>
  30:    e8bd4010     pop    {r4, lr}
  34:    e12fff1e     bx    lr

00000038 <setSomethingElse>:
  38:    e92d4010     push    {r4, lr}
  3c:    e3a00007     mov    r0, #7
  40:    ebfffff1     bl    c <dummy>
  44:    e8bd4010     pop    {r4, lr}
  48:    e12fff1e     bx    lr

0000004c <initModule>:
  4c:    e92d4010     push    {r4, lr}
  50:    ebffffee     bl    10 <setCLK>
  54:    ebfffff2     bl    24 <setConfig>
  58:    ebfffff6     bl    38 <setSomethingElse>
  5c:    e8bd4010     pop    {r4, lr}
  60:    e12fff1e     bx    lr

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

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

यह कुछ संभव पठनीयता के साथ ज्यादातर रखरखाव और सॉफ्टवेयर डिजाइन का मामला बन जाता है। रख-रखाव, पठनीयता, और प्रदर्शन आपके पास नहीं हो सकते हैं; आप एक बार में केवल एक या दो उठा सकते हैं, तीनों नहीं।

यह एक राय आधारित प्रश्न है, और उपरोक्त तीन प्रमुख तरीकों से पता चलता है कि यह जा सकता है। क्या रास्ता सबसे अच्छा है कि सख्ती से राय है। क्या सभी कार्य एक ही कार्य में हो रहे हैं? एक राय आधारित प्रश्न, कुछ लोग प्रदर्शन के लिए दुबले हो जाते हैं, कुछ प्रतिरूपकता और उनके पठनीयता के संस्करण को BEST के रूप में परिभाषित करते हैं। बहुत सारे लोग जिसे पठनीयता कहते हैं, उसके साथ दिलचस्प मुद्दा बेहद दर्दनाक है; कोड को "देखने" के लिए आपके पास एक बार में 50-10,000 फाइलें होनी चाहिए और किसी भी तरह से जो चल रहा है उसे देखने के लिए निष्पादन क्रम में कार्यों को रैखिक रूप से देखने का प्रयास करें। मुझे लगता है कि पठनीयता के विपरीत है, लेकिन दूसरों को यह पठनीय लगता है क्योंकि प्रत्येक आइटम स्क्रीन / संपादक विंडो पर फिट बैठता है और पूरी तरह से उपभोग किया जा सकता है क्योंकि उन्होंने कॉल किए जा रहे कार्यों को याद किया है और / या एक संपादक है जो पॉप और आउट कर सकता है एक परियोजना के भीतर प्रत्येक कार्य।

जब आप विभिन्न समाधान देखते हैं तो यह एक बड़ा कारक है। टेक्स्ट एडिटर, आईडीई आदि बहुत ही व्यक्तिगत हैं, और यह vi बनाम Emacs से आगे निकल जाता है। प्रोग्रामिंग दक्षता, प्रति दिन / महीने की लाइनें ऊपर जाती हैं यदि आप उस उपकरण के साथ सहज और कुशल हैं जो आप उपयोग कर रहे हैं। उपकरण की विशेषताएं जानबूझकर या उस टूल के प्रशंसकों के कोड लिखने के तरीके के प्रति जानबूझकर या झुक नहीं सकती हैं। और परिणामस्वरूप यदि कोई व्यक्ति इन पुस्तकालयों को लिख रहा है तो परियोजना कुछ हद तक इन आदतों को दर्शाती है। यहां तक ​​कि अगर यह एक टीम है, तो लीडर डेवलपर या बॉस की आदतों / वरीयताओं को बाकी टीम पर मजबूर किया जा सकता है।

कोडिंग मानकों में बहुत सारी व्यक्तिगत प्राथमिकताएँ होती हैं, बहुत धार्मिक vi बनाम Emacs फिर से, टैब बनाम रिक्त स्थान, कैसे कोष्ठक पंक्तिबद्ध होते हैं, आदि और ये पुस्तकालयों में कुछ हद तक कैसे डिज़ाइन किए जाते हैं।

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

आप पहली बार बल्लेबाजी करते हुए होम रन नहीं मार रहे हैं। आपकी शैली को सही मायने में परिभाषित करने में दशकों लग सकते हैं। उसी समय, उस समय के दौरान, आपकी शैली बदल सकती है, एक तरह से कुछ समय के लिए झुकाव, फिर दूसरा झुकाव।

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

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


4
वास्तव में? "कुछ लक्ष्य" और "कुछ संकलक" क्या आप उपयोग करते हैं मैं पूछ सकता हूं?
डोरियन

यह मुझे एक 32/64 बिट ARM8 की तरह दिखता है, शायद एक रास्पबेरी पीआई से फिर एक सामान्य माइक्रोकंट्रोलर। क्या आपने प्रश्न में पहला वाक्य पढ़ा है?
डोरियन

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

अगर कोई सोच रहा है कि कौन सा कंपाइलर फाइल गैप्स में ऑप्टिमाइज़ कर सकता है: IAR कंपाइलर्स मल्टी फाइल कॉम्प्लेक्शन (जिसे वे इसे कहते हैं) का समर्थन करते हैं, जो क्रॉस फाइल ऑप्टिमाइजेशन की अनुमति देता है। यदि आप एक बार में सभी c / cpp फ़ाइलों को फेंक देते हैं, तो आप एक निष्पादन योग्य के साथ समाप्त होते हैं जिसमें एक एकल फ़ंक्शन होता है: मुख्य। प्रदर्शन लाभ काफी गहरा हो सकता है।
आर्सेनल

3
@Arsenal कोर्स gcc inlining का समर्थन करता है, यहाँ तक कि संकलन इकाइयों के पार भी अगर ठीक से कहा जाए। Gcc.gnu.org/onbuildocs/gcc/Optimize-Options.html देखें और -flto विकल्प खोजें।
पीटर -

1

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


अफसोस की बात है कि आज अधिकांश प्रोग्रामर के लिए यह सच है।
डोरियन

0

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


आपके जवाब के लिए धन्यवाद। अगर प्रदर्शन के लिए जरूरत है तो मैं शैली बदल सकता हूं लेकिन क्या यहां सवाल यह है कि कोड की पठनीयता प्रदर्शन को प्रभावित करती है?
MaNyYaCk

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

@Humpawumpa - यदि आप केवल 256 या 64 बाइट की रैम के साथ एक माइक्रोकंट्रोलर के लिए लिख रहे हैं तो फ़ंक्शन कॉल की एक दर्जन परतें एक नगण्य बलिदान नहीं है, यह सिर्फ संभव नहीं है
uɐɪ

हां, लेकिन ये दो चरम सीमाएं हैं ... आमतौर पर आपके पास 256 से अधिक बाइट्स हैं और एक दर्जन से भी कम परतों का उपयोग कर रहे हैं - उम्मीद है।
कविता

0

यदि कोई फ़ंक्शन वास्तव में केवल एक बहुत छोटी चीज करता है, तो इसे बनाने पर विचार करें static inline

C फ़ाइल के बजाय इसे हेडर फ़ाइल में जोड़ें, और static inlineइसे परिभाषित करने के लिए शब्दों का उपयोग करें :

static inline void setCLK()
{
    //code to set the clock
}

अब, यदि फ़ंक्शन थोड़ा अधिक लंबा है, जैसे कि 3 रेखाओं से अधिक होने पर, इसे static inline.c फ़ाइल से बचने और जोड़ने के लिए एक अच्छा विचार हो सकता है । आखिरकार, एम्बेडेड सिस्टम में सीमित मेमोरी होती है, और आप कोड आकार को बहुत अधिक नहीं बढ़ाना चाहते हैं।

इसके अलावा, यदि आप फ़ंक्शन को file1.cइसमें से परिभाषित करते हैं और इसका उपयोग करते हैं file2.c, तो संकलक स्वचालित रूप से इसे इनलाइन नहीं करेगा। हालाँकि, यदि आप इसे file1.hएक static inlineफ़ंक्शन के रूप में परिभाषित करते हैं, तो संभावना है कि आपके कंपाइलर इसे इनलाइन करते हैं।

ये static inlineकार्य उच्च-प्रदर्शन प्रोग्रामिंग में अत्यंत उपयोगी हैं। मैंने उन्हें तीन से अधिक के कारक द्वारा अक्सर कोड प्रदर्शन बढ़ाने के लिए पाया है।


"जैसे कि 3 से अधिक लाइनें" - लाइन की गिनती का इससे कोई लेना-देना नहीं है; इनलाइन लागत में सब कुछ है। मैं एक 20-लाइन फ़ंक्शन लिख सकता हूं जो कि इनलाइनिंग के लिए एकदम सही है, और एक 3-लाइन फ़ंक्शन जो कि इनलाइनिंग के लिए भयानक है (जैसे फ़ंक्शनए () जो फ़ंक्शन बीसीबी () 3 बार, फ़ंक्शनबी) (जिसे फ़ंक्शन कॉल करता है) (3 बार) और अन्य स्तरों के एक जोड़े)।
जेसन एस

इसके अलावा, यदि आप फ़ंक्शन को file1.cइसमें से परिभाषित करते हैं और इसका उपयोग करते हैं file2.c, तो संकलक स्वचालित रूप से इसे इनलाइन नहीं करेगा। झूठा । उदाहरण -fltoके लिए gcc या clang में देखें ।
बेरेन्डी - विरोध कर रहा है

0

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

उदाहरण के लिए, यदि एक एकल-कोर प्रणाली में रुकावट सेवा दिनचर्या [एक टाइमर टिक या जो कुछ भी हो] के साथ है:]

volatile uint32_t *magic_write_ptr,magic_write_count;
void handle_interrupt(void)
{
  if (magic_write_count)
  {
    magic_write_count--;
    send_data(*magic_write_ptr++)
  }
}

पृष्ठभूमि लेखन ऑपरेशन शुरू करने के लिए फ़ंक्शन लिखना संभव है या इसके पूरा होने की प्रतीक्षा करना चाहिए:

void wait_for_background_write(void)
{
  while(magic_write_count)
    ;
}
void start_background_write(uint32_t *dat, uint32_t count)
{
  wait_for_background_write();
  background_write_ptr = dat;
  background_write_count = count;
}

और फिर ऐसे कोड का उपयोग करके आह्वान करें:

uint32_t buff[16];

... write first set of data into buff
start_background_write(buff, 16);
... do some stuff unrelated to buff
wait_for_background_write();

... write second set of data into buff
start_background_write(buff, 16);
... etc.

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

मानक जानबूझकर गुणवत्ता-के-कार्यान्वयन के मुद्दों की अनदेखी करता है, यह अनुमान लगाता है कि उपरोक्त निर्माण को संभालने के कई उचित तरीके हैं:

  1. उच्च-स्तरीय संख्या क्रंचिंग जैसे क्षेत्रों के लिए विशेष रूप से लक्षित एक गुणवत्ता कार्यान्वयन उचित उम्मीद कर सकता है कि ऐसे क्षेत्रों के लिए लिखे गए कोड में उपरोक्त जैसे निर्माण नहीं होंगे।

  2. एक गुणवत्ता कार्यान्वयन volatileवस्तुओं तक सभी पहुंच का इलाज कर सकता है, क्योंकि वे उन कार्यों को ट्रिगर कर सकते हैं जो बाहरी दुनिया को दिखाई देने वाली किसी भी वस्तु तक पहुंचेंगे।

  3. एम्बेडेड सिस्टम के उपयोग के लिए एक सरल लेकिन सभ्य-गुणवत्ता वाला कार्यान्वयन "इनलाइन" के रूप में चिह्नित नहीं किए गए फ़ंक्शंस के लिए सभी कॉल का इलाज कर सकता है, हालांकि वे बाहरी दुनिया के सामने आने वाली किसी भी वस्तु का उपयोग कर सकते हैं, भले ही वह volatile# में वर्णित नहीं है। 2।

मानक यह सुझाव देने का कोई प्रयास नहीं करता है कि गुणवत्ता के कार्यान्वयन के लिए उपरोक्त दृष्टिकोणों में से कौन सा सबसे उपयुक्त होगा, और न ही यह सुनिश्चित करने के लिए कि "अनुरूप" कार्यान्वयन किसी विशेष उद्देश्य के लिए उपयोग किए जाने के लिए पर्याप्त रूप से अच्छी गुणवत्ता के हों। नतीजतन, gcc या clang जैसे कुछ संकलक को प्रभावी रूप से यह आवश्यक है कि इस पैटर्न का उपयोग करने के लिए इच्छुक किसी भी कोड को कई अनुकूलन अक्षमताओं के साथ संकलित किया जाना चाहिए।

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


"यह सुनिश्चित करना कि I / O फ़ंक्शंस एक अलग संकलन इकाई में हैं" ... इन जैसे अनुकूलन समस्याओं को रोकने का एक निश्चित तरीका नहीं है। कम से कम एलएलवीएम और मेरा मानना ​​है कि जीसीसी कई मामलों में पूरे कार्यक्रम का अनुकूलन करेगा, इसलिए आपके आईओ कार्यों को इनलाइन करने का निर्णय ले सकता है, भले ही वे एक अलग संकलन इकाई में हों।
जूल्स

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

@ जूल्स: एम्बेडेड या सिस्टम प्रोग्रामिंग के लिए एक उच्च-गुणवत्ता का कार्यान्वयन शब्दार्थ के लिए उपयुक्त होना चाहिए जो उस उद्देश्य के लिए उपयुक्त हों, जिसमें संपूर्ण-प्रोग्राम ऑप्टिमाइज़ेशन को पूरी तरह से अक्षम किया जा सके (जैसे कि volatileएक्सेस का इलाज करने का विकल्प होने के बावजूद वे संभावित रूप से ट्रिगर हो सकते हैं। अन्य वस्तुओं के लिए मनमाने ढंग से पहुंच), लेकिन जो भी कारण के लिए gcc और clang बल्कि बेकार के फैशन में व्यवहार करने के निमंत्रण के रूप में गुणवत्ता के कार्यान्वयन के मुद्दों का इलाज करेगा।
सुपरकैट

1
यहां तक ​​कि "उच्चतम गुणवत्ता" का कार्यान्वयन छोटी गाड़ी कोड को सही नहीं करेगा। यदि buffघोषित नहीं किया जाता है volatile, तो इसे एक अस्थिर चर के रूप में नहीं माना जाएगा, इसे एक्सेस करने पर इसे फिर से चालू या अनुकूलित किया जा सकता है यदि स्पष्ट रूप से बाद में उपयोग किया जाता है। नियम सरल है: उन सभी चरों को चिह्नित करें जिन्हें सामान्य प्रोग्राम प्रवाह (जैसा कि कंपाइलर द्वारा देखा गया है) के बाहर एक्सेस किया जा सकता है volatile। क्या buffएक बाधा हैंडलर में प्रवेश की सामग्री है ? हाँ। तो यह होना चाहिए volatile
बेर्न्डी -

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