C मानक अनुकूलन करने के लिए बहुत सारे अक्षांशों को संकलक देता है। इन अनुकूलन के परिणाम आश्चर्यजनक हो सकते हैं यदि आप उन कार्यक्रमों के एक भोले मॉडल को मानते हैं जहां अनैतिक स्मृति कुछ यादृच्छिक बिट पैटर्न पर सेट होती है और उनके लिखे जाने के क्रम में सभी ऑपरेशन किए जाते हैं।
नोट: निम्नलिखित उदाहरण केवल मान्य हैं क्योंकि x
इसका पता कभी नहीं लिया गया है, इसलिए यह "रजिस्टर-लाइक" है। यदि उनके x
पास ट्रैप अभ्यावेदन का प्रकार है तो वे भी मान्य होंगे ; यह शायद ही कभी अहस्ताक्षरित प्रकारों के लिए होता है (इसमें कम से कम एक बिट भंडारण के लिए "बर्बाद करना" आवश्यक होता है, और इसे प्रलेखित किया जाना चाहिए), और इसके लिए असंभव है unsigned char
। यदि x
कोई हस्ताक्षरित प्रकार था, तो कार्यान्वयन बिट पैटर्न को परिभाषित कर सकता है जो कि एक संख्या नहीं है - (2 एन -1 -1) और 2 एन -1 -1 एक जाल प्रतिनिधित्व के रूप में। देखिए जेन्स गुस्तेद का जवाब ।
कंपाइलर रजिस्टरों को वेरिएबल्स में असाइन करने की कोशिश करते हैं, क्योंकि रजिस्टर मेमोरी की तुलना में तेज होते हैं। चूंकि प्रोग्राम में प्रोसेसर की तुलना में अधिक चर का उपयोग हो सकता है, इसलिए कंपाइलर रजिस्टर आवंटन का प्रदर्शन करते हैं, जिसके कारण अलग-अलग समय में एक ही रजिस्टर का उपयोग करके अलग-अलग चर होते हैं। कार्यक्रम के टुकड़े पर विचार करें
unsigned x, y, z;
y = 0;
z = 4;
x = - x;
y = y + z;
x = y + 1;
जब लाइन 3 का मूल्यांकन किया जाता है, तो x
इसे अभी तक आरंभ नहीं किया जाता है, इसलिए (कंपाइलर का कारण) लाइन 3 कुछ प्रकार की होनी चाहिए, जो अन्य स्थितियों के कारण नहीं हो सकती है जो संकलक का पता लगाने के लिए पर्याप्त स्मार्ट नहीं था। चूंकि z
लाइन 4 के बाद उपयोग नहीं किया जाता है, और x
लाइन 5 से पहले उपयोग नहीं किया जाता है, इसलिए समान रजिस्टर का उपयोग दोनों चर के लिए किया जा सकता है। इसलिए इस छोटे से कार्यक्रम को रजिस्टरों के निम्नलिखित कार्यों के लिए संकलित किया गया है:
r1 = 0;
r0 = 4;
r0 = - r0;
r1 += r0;
r0 = r1;
का अंतिम मान x
अंतिम मान है r0
, और अंतिम मूल्य का y
अंतिम मूल्य है r1
। ये मान x = -3 और y = -4 हैं, और 5 और 4 नहीं हैं जैसा कि अगर x
ठीक से आरंभीकृत किया गया होता ।
अधिक विस्तृत उदाहरण के लिए, निम्नलिखित कोड के टुकड़े पर विचार करें:
unsigned i, x;
for (i = 0; i < 10; i++) {
x = (condition() ? some_value() : -x);
}
मान लीजिए कि संकलक पता लगाता है कि condition
कोई दुष्प्रभाव नहीं है। चूंकि condition
संशोधित नहीं होता है x
, इसलिए कंपाइलर जानता है कि लूप के माध्यम से पहला रन संभवत: एक्सेस नहीं किया जा सकता है x
क्योंकि यह अभी तक आरंभीकृत नहीं है। इसलिए लूप बॉडी का पहला निष्पादन के बराबर है x = some_value()
, हालत का परीक्षण करने की कोई आवश्यकता नहीं है। कंपाइलर इस कोड को संकलित कर सकता है जैसे कि आपने लिखा है
unsigned i, x;
i = 0;
x = some_value();
for (i = 1; i < 10; i++) {
x = (condition() ? some_value() : -x);
}
जिस तरह से इस संकलक के अंदर तैयार किया जा सकता है पर विचार करने के लिए कि के आधार पर किसी भी मूल्य है x
है जो कुछ भी मूल्य सुविधाजनक है जब तक x
अप्रारंभीकृत है। चूँकि व्यवहार जब एक अनियंत्रित चर अपरिभाषित होता है, तो चर के बजाय केवल अनिर्दिष्ट मूल्य होने के कारण, संकलक को जो कुछ भी सुविधाजनक मान है, के बीच किसी विशेष गणितीय संबंध पर नज़र रखने की आवश्यकता नहीं है। इस प्रकार संकलक ऊपर दिए गए कोड का इस प्रकार विश्लेषण कर सकता है:
- पहले लूप पुनरावृत्ति के दौरान,
x
समय -x
का मूल्यांकन किया जाता है।
-x
अपरिभाषित व्यवहार किया है, इसलिए इसका मूल्य जो भी है-सुविधाजनक है।
- अनुकूलन नियम लागू होता है, इसलिए इस कोड को सरल बनाया जा सकता है ।
condition ? value : value
condition; value
जब आपके प्रश्न में कोड के साथ सामना किया जाता है, तो यह उसी संकलक का विश्लेषण करता है कि जब x = - x
मूल्यांकन किया जाता है, तो -x
जो कुछ भी है वह सुविधाजनक है। तो असाइनमेंट दूर अनुकूलित किया जा सकता है।
मैंने एक संकलक के उदाहरण की तलाश नहीं की है जो ऊपर वर्णित के अनुसार व्यवहार करता है, लेकिन यह उस तरह का अनुकूलन है जो अच्छे संकलक करने की कोशिश करते हैं। मैं एक का सामना करने के लिए आश्चर्यचकित नहीं होगा। यहां एक संकलक का कम प्रशंसनीय उदाहरण है जिसके साथ आपका प्रोग्राम क्रैश हो जाता है। (यदि आप किसी तरह के उन्नत डिबगिंग मोड में अपने प्रोग्राम को संकलित करते हैं, तो ऐसा नहीं हो सकता है।)
यह काल्पनिक संकलक प्रत्येक चर को एक अलग मेमोरी पेज में मैप करता है और पेज की विशेषताओं को सेट करता है ताकि एक असिंचित चर से पढ़ने से एक प्रोसेसर ट्रैप हो जाता है जो डिबगर को आमंत्रित करता है। एक चर के लिए कोई भी असाइनमेंट पहले सुनिश्चित करता है कि उसका मेमोरी पेज सामान्य रूप से मैप किया गया है। यह संकलक किसी भी उन्नत अनुकूलन को करने की कोशिश नहीं करता है - यह एक डिबगिंग मोड में है, जिसका उद्देश्य आसानी से असंसाधित चर जैसे बग का पता लगाना है। जब x = - x
मूल्यांकन किया जाता है, तो दाएं हाथ की तरफ जाल का कारण बनता है और डिबगर ऊपर फायर करता है।