ऑनलाइन आईडीई पर अजीब व्यवहार करने वाला कार्यक्रम


82

मैं नीचे सी + + कार्यक्रम ( स्रोत ) में आया हूं :

#include <iostream>
int main()
{
    for (int i = 0; i < 300; i++)
        std::cout << i << " " << i * 12345678 << std::endl;
}

यह एक साधारण प्रोग्राम की तरह दिखता है और मेरे स्थानीय मशीन पर सही आउटपुट देता है, जैसे कि:

0 0
1 12345678
2 24691356
...
297 -628300930
298 -615955252
299 -603609574

लेकिन, कोडेक की तरह ऑनलाइन आईडीई पर , यह निम्नलिखित आउटपुट देता है:

0 0
1 12345678
2 24691356
...
4167 -95167326
4168 -82821648
4169 -7047597

forलूप 300 पर समाप्त क्यों नहीं होता है ? साथ ही यह कार्यक्रम हमेशा समाप्त होता है 41694169कुछ और मूल्य क्यों और कैसे?


45
शायद इसलिए कि हस्ताक्षरित पूर्णांक अतिप्रवाह में अपरिभाषित व्यवहार होता है।
एरोरिका

17
मुझे पता है कि अतिप्रवाहित हस्ताक्षर UB है, लेकिन यह एक शानदार असफलता है ...
गैलिक

45
UB को न मानने का एक अच्छा सबक है
MM

12
मैं उत्सुक हूं कि आप ऐसा क्यों सोचते हैं कि पहला आउटपुट "सही आउटपुट" है।
लाइटवेज़ दौड़ कक्षा

5
@LightnessRacesinOrbit - अच्छी तरह से, कि अनुस्मारक है मूल्यवान!
davidbak

जवाबों:


108

मैं मान रहा हूं कि ऑनलाइन कंपाइलर GCC या कम्पैटिबल कंपाइलर का उपयोग करते हैं। बेशक, किसी भी अन्य संकलक को भी समान अनुकूलन करने की अनुमति है, लेकिन जीसीसी प्रलेखन अच्छी तरह से बताता है कि यह क्या करता है:

-faggressive-loop-optimizations

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

यह विकल्प केवल उन मामलों के आधार पर धारणा बनाने की अनुमति देता है जहां यूबी साबित होता है। उन मान्यताओं का लाभ उठाने के लिए, अन्य अनुकूलन को सक्षम करने की आवश्यकता हो सकती है, जैसे कि निरंतर तह।


हस्ताक्षरित पूर्णांक अतिप्रवाह में अपरिभाषित व्यवहार होता है। ऑप्टिमाइज़र यह साबित करने में सक्षम था कि i173 से अधिक का कोई भी मूल्य यूबी का कारण होगा, और क्योंकि यह मान सकता है कि कोई यूबी नहीं है, यह भी मान सकता है कि iयह 173 से अधिक नहीं है। यह आगे साबित कर सकता है किi < 300 हमेशा सच है, और इसलिए लूप की स्थिति को दूर अनुकूलित किया जा सकता है।

4169 और कुछ अन्य मूल्य क्यों नहीं?

वे साइटें संभवतः उन आउटपुट लाइनों (या वर्णों या बाइट्स) की संख्या को सीमित करती हैं जो वे दिखाती हैं और उसी सीमा को साझा करने के लिए होती हैं।


3
यदि संकलक साबित कर सकता है कि i173 से अधिक के किसी भी मूल्य के लिए यूबी होगा , तो यह व्यर्थ अनुकूलन करने के बजाय चेतावनी क्यों नहीं देता है?
Jabberwocky

7
@MichaelWalz यह एक उत्सर्जन करता है।
होलीब्लैककैट

3
@MichaelWalz: निरर्थक बूलियन परीक्षणों को हटाना एक व्यर्थ अनुकूलन नहीं है; यह बहुत उपयोगी है। क्या होगा (ज्यादातर) व्यर्थ टूटे स्रोत कोड की उपस्थिति में अनुकूलन को अक्षम / अक्षम करने के लिए अतिरिक्त कोड जोड़ रहा है।

25
@MichaelWalz: कंपाइलर विश्वसनीय रूप से यूबी का पता नहीं लगा सकता है जैसा कि आप सुझाव देते हैं (हालांकि यह कभी-कभी संभावित घटना पर चेतावनी दे सकता है, क्योंकि यह वास्तव में यहां होता है)। इसके बजाय, यह इस धारणा पर सबसे अच्छे इरादों के साथ आगे बढ़ सकता है कि यूबी नहीं होगा । वे दो शायद सूक्ष्म रूप से हैं, लेकिन वास्तव में काफी अलग चीजें हैं। यह ऐसा नहीं है कि संकलक "अहा! यूबी! अब मैं इस तरह के और इस तरह के अनुकूलन को चालू कर सकता हूं " - अनुकूलन हमेशा था। यह हर समय इस तरह से सामान कर रहा है । लेकिन, जब तक आपका कार्यक्रम सही ढंग से लिखा गया है, तब तक आप इसके बदलावों के बारे में कोई बदलाव नहीं देखेंगे।
ऑर्बिट में लाइटनेस दौड़

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

40

"अपरिभाषित व्यवहार अपरिभाषित है।" (सी)

कोडक पर प्रयुक्त एक कंपाइलर निम्नलिखित तर्क का उपयोग करता है:

  1. अपरिभाषित व्यवहार नहीं हो सकता।
  2. i * 12345678यूबी में ओवरफ्लो और परिणाम यदि i > 173(32 बिट intएस मान रहा है )।
  3. इस प्रकार, iकभी भी अधिक नहीं हो सकता 173
  4. इस प्रकार शानदार i < 300है और इसके साथ प्रतिस्थापित किया जा सकता है true

पाश स्वयं अनंत प्रतीत होता है। जाहिर है, codechef समय की एक विशिष्ट राशि के बाद कार्यक्रम बंद कर देता है या उत्पादन को छोटा करता है।


11
@ArpanMangal मैंने केवल आउटपुट में वर्णों को गिना है, और ऐसा लगता है 2^16। जाहिर है कि यह एक संयोग है कि दोनों ही 2^16पात्रों को आउटपुट देते हैं।
होलीब्लैकैट

3
@ArpanMangal: 4169 जैसे नाक के राक्षस, और वर्तमान में विचारधारा और कोडेक पर पार्टी कर रहे हैं। यूबी अपरिभाषित है, यह नाक राक्षसों सहित कुछ भी हो सकता है। सभी गंभीरता में, यूबी का विश्लेषण करने की कोशिश करना समय की बर्बादी है, उस समय का उपयोग यह जानने के लिए करें कि इसे कैसे रखा जाए।
15

6
@jmoreno यह समय की बर्बादी नहीं है यदि आप संकलक डिजाइन में रुचि रखते हैं
user253751

2
@jmoreno हालांकि, इस बार इसका विश्लेषण करना संभव था। यह समझने में कि वास्तव में UB कैसे सामान तोड़ता है, यह निष्कर्ष निकालने के लिए उपयोगी हो सकता है कि यूबी स्वीकार्य है, यदि कोई हो।
HolyBlackCat

4
@jmoreno ब्रह्मांड जो कुछ भी करता है वह सही है (परिभाषा के अनुसार), इसलिए खगोल विज्ञान का अध्ययन करने का क्या मतलब है?
user253751

11

आप अपने लूप के अंदर 174 वें पुनरावृत्ति पर अपरिभाषित व्यवहार को लागू कर रहे हैं forक्योंकि अधिकतम intमूल्य शायद 2147483647अभी तक 174 * 123456789अभिव्यक्ति का मूल्यांकन है 2148147972जो अपरिभाषित व्यवहार है क्योंकि कोई हस्ताक्षरित पूर्णांक अतिप्रवाह नहीं है। तो आप यूबी के प्रभावों को देख रहे हैं, विशेष रूप से आपके मामले में सेट किए गए अनुकूलन झंडे के साथ जीसीसी संकलक के साथ। यह संभावना है कि संकलक ने आपको निम्नलिखित चेतावनी जारी करके इस बारे में चेतावनी दी होगी:

warning: iteration 174 invokes undefined behavior [-Waggressive-loop-optimizations]

-O2विभिन्न परिणामों का निरीक्षण करने के लिए ( ) अनुकूलन फ्लैगशिप निकालें ।


4
यह ध्यान देने योग्य है कि अपरिभाषित व्यवहार का पूर्वव्यापी प्रभाव हो सकता है - क्योंकि यूबी 174 पर होगा, मानक को यह भी आवश्यकता नहीं है कि लूप के पहले 173 पुनरावृत्तियों को अपेक्षित रूप से आगे बढ़ना चाहिए!

@ हर्किल वास्तव में। यह कुछ हद तक विरोधाभासी है कि यूबी पूरे कार्यक्रम का कारण बनता है, जिसमें यूबी प्रदर्शित करने के लिए पिछले कथन भी शामिल हैं।
रॉन

12
@ रॉन: यह विरोधाभासी नहीं है। या तो कार्यक्रम में अच्छी तरह से परिभाषित शब्दार्थ है, या यह नहीं है। अवधि। याद रखें, C ++ कोड को किए जाने वाले निर्देशों का अनुक्रम नहीं है; यह एक कार्यक्रम का विवरण है
लाइटवेट दौड़ कक्षा

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

@ सुपरकैट: वास्तव में, अनिर्दिष्ट व्यवहार अपरिभाषित व्यवहार के समान नहीं है। हम
ऑर्बिट

7

संकलक मान सकता है कि अपरिभाषित व्यवहार नहीं होगा, और क्योंकि हस्ताक्षरित अतिप्रवाह यूबी है, यह मान सकता है कि कभी नहीं i * 12345678 > INT_MAX, इसलिए भी i <= INT_MAX / 12345678 < 300और इसलिए चेक को हटा दें i < 300

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.