UB के अधिकांश प्रकार, जिनके बारे में हम आमतौर पर चिंता करते हैं, जैसे NULL-deref या शून्य से विभाजित, रनटाइम UB हैं। एक फ़ंक्शन को संकलित करना जो रनटाइम यूबी का कारण होगा यदि निष्पादित होने पर कंपाइलर को दुर्घटना का कारण नहीं होना चाहिए। जब तक शायद यह साबित नहीं हो सकता कि कार्य (और फ़ंक्शन के माध्यम से पथ) निश्चित रूप से कार्यक्रम द्वारा निष्पादित किया जाएगा ।
(2 विचार: हो सकता है कि मैंने संकलन समय पर टेम्प्लेट / कॉन्स्टैक्स आवश्यक मूल्यांकन पर विचार नहीं किया है। संभवतः उस दौरान यूबी को अनुवाद के दौरान मनमाने ढंग से अजीबता पैदा करने की अनुमति दी जाती है, भले ही परिणामी फ़ंक्शन को कभी नहीं कहा जाता हो।)
अनुवाद के दौरान व्यवहार आईएसओ सी ++ बोली का हिस्सा में @ कथाकार के जवाब आईएसओ सी मानक में प्रयुक्त भाषा के समान है। C constexpr
संकलन समय पर टेम्प्लेट या अनिवार्य eval शामिल नहीं करता है ।
लेकिन मजेदार तथ्य : आईएसओ सी एक नोट में कहता है कि यदि अनुवाद को समाप्त कर दिया जाता है, तो यह एक नैदानिक संदेश के साथ होना चाहिए। या "अनुवाद के दौरान व्यवहार ... एक दस्तावेज तरीके से"। मुझे नहीं लगता कि "स्थिति को पूरी तरह से अनदेखा करना" अनुवाद को रोकने के रूप में पढ़ा जा सकता है।
पुराने उत्तर, अनुवाद से पहले मैंने UB के बारे में सीखा। यह रनटाइम-यूबी के लिए सही है, हालांकि, और इस प्रकार संभावित रूप से अभी भी उपयोगी है।
यूबी जैसी कोई चीज नहीं है जो संकलन के समय होती है। यह संकलक को निष्पादन के एक निश्चित मार्ग के साथ दिखाई दे सकता है , लेकिन C ++ शर्तों में ऐसा नहीं हुआ है जब तक कि निष्पादन एक फ़ंक्शन के माध्यम से निष्पादन के उस पथ तक नहीं पहुंचता है।
एक प्रोग्राम में दोष, जो इसे असंभव बनाना भी यूबी नहीं है, वे वाक्यविन्यास त्रुटियां हैं। इस तरह के एक कार्यक्रम सी ++ शब्दावली में "अच्छी तरह से गठित नहीं है" (यदि मेरे पास मेरा मानक सही है)। एक कार्यक्रम अच्छी तरह से बन सकता है लेकिन इसमें यूबी होता है। अपरिभाषित व्यवहार और बीमार गठन के बीच अंतर, कोई नैदानिक संदेश की आवश्यकता नहीं है
जब तक मैं कुछ गलत नहीं कर रहा हूं, आईएसओ सी ++ को इस कार्यक्रम को सही ढंग से संकलित करने और निष्पादित करने की आवश्यकता है, क्योंकि निष्पादन कभी भी शून्य से विभाजन तक नहीं पहुंचता है। (अभ्यास (में Godbolt ), अच्छा compilers सिर्फ काम कर निष्पादनयोग्य बनाते हैं। जीसीसी / बजना के बारे में चेतावनी x / 0
लेकिन इस, तब भी जब के अनुकूलन। लेकिन वैसे भी, हम बताने के लिए कोशिश कर रहे हैं कम आईएसओ सी ++ कार्यान्वयन की गुणवत्ता होने के लिए अनुमति देता है। तो जीसीसी जाँच / क्लैंग शायद ही एक उपयोगी परीक्षण है जो पुष्टि करता है कि मैंने कार्यक्रम को सही ढंग से लिखा है।
int cause_UB() {
int x=0;
return 1 / x;
}
int main(){
if (0)
cause_UB();
}
इसके लिए एक उपयोग-केस में सी प्रीप्रोसेसर, या constexpr
चर और उन चरों पर ब्रांचिंग शामिल हो सकती है , जो कुछ रास्तों में बकवास की ओर जाता है जो स्थिरांक के उन विकल्पों के लिए कभी नहीं पहुंचते हैं।
निष्पादन के पथ जो संकलन-समय-दृश्यमान UB का कारण बनते हैं, उन्हें कभी भी ग्रहण नहीं किया जा सकता है, उदाहरण के लिए x86 के लिए संकलक ud2
परिभाषा के रूप में (अवैध अनुदेश अपवाद का कारण) का उत्सर्जन कर सकता है cause_UB()
। या एक फ़ंक्शन के भीतर, यदि यूबी if()
को साबित करने के लिए लीड की एक तरफ , शाखा को हटाया जा सकता है।
लेकिन कंपाइलर को अभी भी बाकी सभी चीज़ों को सही और सही तरीके से संकलित करना है । सभी पथ जो एनकाउंटर नहीं करते हैं (या मुठभेड़ के लिए सिद्ध नहीं किए जा सकते हैं) यूबी को अभी भी एएसएम के लिए संकलित किया जाना चाहिए, जैसे कि सी ++ एब्सट्रैक्ट मशीन इसे चला रही थी।
आप तर्क दे सकते हैं कि बिना शर्त संकलन-समय-दृश्यमान UB main
इस नियम का अपवाद है। या अन्यथा संकलन-समय-सिद्ध है कि निष्पादन शुरू होने की main
गारंटी यूबी तक पहुंचती है।
मैं अभी भी तर्क देता हूं कि कानूनी संकलक व्यवहार में एक ग्रेनेड का उत्पादन शामिल है जो अगर चलता है तो विस्फोट होता है । या अधिक प्रशंसनीय, इसकी एक परिभाषा main
में एक एकल अवैध निर्देश शामिल हैं। मेरा तर्क है कि यदि आप कभी भी कार्यक्रम नहीं चलाते हैं, तो अभी तक कोई यूबी नहीं हुआ है। संकलक को स्वयं विस्फोट करने की अनुमति नहीं है, IMO।
शाखाओं के अंदर संभव या सिद्ध यूबी युक्त कार्य
यूबी निष्पादन के किसी भी मार्ग पर पिछले सभी कोड को "दूषित" करने के लिए समय पर पीछे की ओर पहुंचता है। लेकिन व्यवहार में संकलक केवल उस नियम का लाभ उठा सकते हैं जब वे वास्तव में यह साबित कर सकते हैं कि निष्पादन के मार्ग संकलित समय-दृश्यमान यूबी के लिए नेतृत्व करते हैं। जैसे
int minefield(int x) {
if (x == 3) {
*(char*)nullptr = x/0;
}
return x * 5;
}
कंपाइलर को एएसएम बनाना पड़ता है जो x
3 से अधिक सभी के लिए काम करता है, उन बिंदुओं तक जहां x * 5
इंट्रूमिन और INT_MAX पर हस्ताक्षरित ओवरफ्लो यूबी का कारण बनता है। यदि इस फ़ंक्शन को कभी नहीं बुलाया जाता है x==3
, तो बेशक कार्यक्रम में कोई यूबी नहीं है और लिखित रूप में काम करना चाहिए।
हम if(x == 3) __builtin_unreachable();
जीएनयू सी में संकलक को बताने के लिए लिख सकते हैं जो x
निश्चित रूप से 3 नहीं है।
व्यवहार में सामान्य कार्यक्रमों में सभी जगह "माइनफील्ड" कोड होता है। जैसे किसी पूर्णांक द्वारा कोई भी विभाजन कंपाइलर का वादा करता है कि यह गैर-शून्य है। कोई भी सूचक deref कंपाइलर से वादा करता है कि वह गैर-पूर्ण है।