C ++ और अपरिभाषित व्यवहार (UB) में अतिप्रवाह


56

मैं निम्नलिखित की तरह कोड के उपयोग के बारे में सोच रहा हूं

int result = 0;
int factor = 1;
for (...) {
    result = ...
    factor *= 10;
}
return result;

यदि लूप nसमय के साथ पुनरावृत्त होता है, तो ठीक कई बार factorगुणा किया जाता 10है n। हालाँकि, factorकेवल कभी-कभी 10कुल गुणा करने के बाद इसका उपयोग किया जाता है n-1। यदि हम मानते हैं कि factorलूप के अंतिम पुनरावृत्ति को छोड़कर कभी भी ओवरफ्लो नहीं होता है, लेकिन लूप के अंतिम पुनरावृत्ति पर अतिप्रवाह हो सकता है, तो क्या ऐसा कोड स्वीकार्य होना चाहिए? इस मामले में, factorअतिप्रवाह के बाद के मूल्य का कभी भी उपयोग नहीं किया जाएगा।

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

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


5
मैं विषय से हटकर के रूप में इस सवाल को बंद करने की वजह से इस प्रश्न पर होना चाहिए मतदान कर रहा हूँ codereview.stackexchange.com यहाँ नहीं।
केविन एंडरसन

31
@ केविनएंडरसन, यहां कोई मान्य नहीं है, क्योंकि उदाहरण कोड को ठीक करना है, केवल सुधार नहीं किया गया है।
बथशेबा

1
@ हेरोल्ड वे खतरे के करीब हैं।
को ऑर्बिट

1
@LightnessRaceswithMonica: मानक के लेखक ने इरादा किया और उम्मीद की कि विभिन्न प्लेटफार्मों और उद्देश्यों के लिए लागू होने वाले कार्यान्वयन प्रोग्रामर के लिए उपलब्ध शब्दार्थ को उन प्लेटफार्मों और उद्देश्यों के लिए उपयोगी तरीके से विभिन्न कार्यों को संसाधित करेंगे, चाहे मानक उन्हें ऐसा करने की आवश्यकता हो या नहीं। और यह भी कहा कि वे गैर-पोर्टेबल कोड को निष्क्रिय करने की इच्छा नहीं रखते थे। इस प्रकार, प्रश्नों के बीच समानता इस बात पर निर्भर करती है कि किन कार्यान्वयनों को समर्थन देने की आवश्यकता है।
सुपरकैट

2
@supercat कार्यान्वयन-परिभाषित व्यवहारों के लिए सुनिश्चित करें, और यदि आप जानते हैं कि आपके टूलचिन में कुछ विस्तार है जिसका आप उपयोग कर सकते हैं (और आप पोर्टेबिलिटी की परवाह नहीं करते हैं), तो ठीक है। यूबी के लिए? संदिग्ध।
ऑर्बिट

जवाबों:


51

कंपाइलर मान लेते हैं कि एक मान्य C ++ प्रोग्राम में UB नहीं है। उदाहरण के लिए विचार करें:

if (x == nullptr) {
    *x = 3;
} else {
    *x = 5;
}

यदि x == nullptrफिर इसे डिरेल करना और मान प्रदान करना यूबी है। इसलिए एक वैध कार्यक्रम में यह एकमात्र तरीका हो सकता है जब x == nullptrकभी भी सही परिणाम नहीं मिलेगा और कंपाइलर मान सकता है जैसे कि नियम, उपरोक्त इसके बराबर है:

*x = 5;

अब आपके कोड में

int result = 0;
int factor = 1;
for (...) {      // Loop until factor overflows but not more
   result = ...
   factor *= 10;
}
return result;

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

// nothing :(

6
"अनफाइंड बिहेवियर" एक ऐसी अभिव्यक्ति है जिसे हम एसओ के जवाबों में स्पष्ट रूप से समझाए बिना बहुत कुछ सुनते हैं कि यह पूरे कार्यक्रम को कैसे प्रभावित कर सकता है। यह उत्तर चीजों को बहुत स्पष्ट करता है।
गाइल्स-फिलिप पैले

1
और यह एक "उपयोगी अनुकूलन" भी हो सकता है यदि फ़ंक्शन को केवल उन लक्ष्यों के साथ कहा जाता है INT_MAX >= 10000000000, जिसमें एक अलग फ़ंक्शन होता है जिसे मामले INT_MAXमें छोटा कहा जाता है।
आर .. गिटहब स्टॉप हेल्पिंग ICE

2
@ गिल्स-फिलिप्पेइले कई बार मैं चाहता हूं कि हम उस पर एक पोस्ट चिपका सकें। बेनिग्न डेटा दौड़ कैप्चरिंग के लिए मेरे पसंदीदा में से एक है कि वे कितने खराब हो सकते हैं। MySQL में एक शानदार बग रिपोर्ट है जिसे मैं फिर से खोज नहीं सकता हूं - एक बफर ओवरफ्लो चेक जो गलती से यूबी को लागू करता है। एक विशेष संकलक का एक विशेष संस्करण केवल माना जाता है कि यूबी कभी नहीं होता है, और पूरे ओवरफ्लो की जांच को अनुकूलित करता है।
Cort Ammon

1
@ सॉलोमनसालो: मुख्य स्थितियां जहां यूबी विवादास्पद है, वे मानक और कार्यान्वयन के दस्तावेज के कुछ हिस्सों के व्यवहार का वर्णन करते हैं, लेकिन मानक के कुछ अन्य भाग इसे यूबी के रूप में दर्शाते हैं। मानक लिखने से पहले सामान्य अभ्यास संकलक लेखकों के लिए ऐसे कार्यों को सार्थक रूप से संसाधित करने के लिए किया गया था, सिवाय इसके कि जब उनके ग्राहक उन्हें कुछ और करने से लाभान्वित करेंगे, और मुझे नहीं लगता कि मानक के लेखकों ने कभी सोचा था कि संकलक लेखक कुछ और करेंगे। ।
सुपरकैट

2
@ गिल्स-फिलिप्पेला: हर सी प्रोग्रामर को एलएलवीएम ब्लॉग से अपरिभाषित व्यवहार के बारे में जानना चाहिए । यह बताता है कि उदाहरण के लिए हस्ताक्षरित-पूर्णांक ओवरफ्लो UB कैसे संकलक को साबित कर सकता है कि i <= nलूप हमेशा गैर-अनंत होते हैं, जैसे i<nलूप। और int iपहले 4 जी सरणी तत्वों के लिए संभावित रैप सरणी अनुक्रमण पर फिर से हस्ताक्षर करने के बजाय लूप में सूचक चौड़ाई को बढ़ावा दें।
पीटर कॉर्डेस

34

intअतिप्रवाह का व्यवहार अपरिभाषित है।

इससे कोई फर्क नहीं पड़ता कि आप factorलूप बॉडी के बाहर पढ़ते हैं ; अगर यह द्वारा तो फिर अपने कोड के व्यवहार पर overflowed गया है, के बाद, और कुछ हद तक विडंबना से पहले अतिप्रवाह अपरिभाषित है।

एक समस्या जो इस कोड को रखने में उत्पन्न हो सकती है वह यह है कि कंपाइलर्स ऑप्टिमाइज़ेशन के समय अधिक से अधिक आक्रामक हो रहे हैं। विशेष रूप से वे एक ऐसी आदत विकसित कर रहे हैं जहाँ वे मानते हैं कि अपरिभाषित व्यवहार कभी नहीं होता है। ऐसा होने के लिए, वे forलूप को पूरी तरह से हटा सकते हैं।

आप एक उपयोग नहीं कर सकते unsignedके लिए प्रकार factorहालांकि तो आप की अवांछित रूपांतरण के बारे में चिंता नहीं करनी होंगी intकरने के लिए unsignedदोनों युक्त भाव में?


12
@nicomp; क्यों नहीं?
बथशेबा

12
@ गिल्स-फिलिप्पेले: क्या मेरा जवाब आपको नहीं बताता कि यह समस्याग्रस्त है? ओपी के लिए मेरा शुरुआती वाक्य जरूरी नहीं है, लेकिन व्यापक समुदाय और factorअसाइनमेंट में "उपयोग" किया जाता है।
बथशेबा

8
@ गिल्स-
फिलिप्पेइले

1
@ बाथेबा आप सही कह रहे हैं, मुझे आपका जवाब गलत लगा।
गिल्स-फिलिप पैले 13

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

23

वास्तविक दुनिया के आशावादी लोगों पर विचार करना सुखद हो सकता है। लूप अनरोलिंग एक ज्ञात तकनीक है। मूल विचार ऑप लूप का अनियंत्रित होना है

for (int i = 0; i != 3; ++i)
    foo()

पर्दे के पीछे बेहतर तरीके से लागू किया जा सकता है

 foo()
 foo()
 foo()

यह तय सीमा के साथ आसान मामला है। लेकिन आधुनिक संकलक इसे चर सीमाओं के लिए भी कर सकते हैं:

for (int i = 0; i != N; ++i)
   foo();

हो जाता है

__RELATIVE_JUMP(3-N)
foo();
foo();
foo();

जाहिर है कि यह केवल तभी काम करता है जब संकलक जानता है कि एन <= 3। और यहीं से हम मूल प्रश्न पर वापस आते हैं। क्योंकि संकलक जानता है कि हस्ताक्षरित अतिप्रवाह नहीं होता है , यह जानता है कि लूप 32 बिट्स आर्किटेक्चर पर अधिकतम 9 बार निष्पादित कर सकता है। 10^10 > 2^32। इसलिए यह एक 9 पुनरावृत्ति लूप को अनियंत्रित कर सकता है। लेकिन इरादा अधिकतम 10 पुनरावृत्तियों था!

क्या हो सकता है कि आपको एन = 10 के साथ एक विधानसभा निर्देश (9-एन) के लिए एक रिश्तेदार कूदना है, इसलिए -1 की एक ऑफसेट, जो कि कूद का निर्देश है। उफ़। यह अच्छी तरह से परिभाषित C ++ के लिए एक पूरी तरह से वैध लूप ऑप्टिमाइज़ेशन है, लेकिन दिया गया उदाहरण एक तंग अनंत लूप में बदल जाता है।


9

किसी भी हस्ताक्षरित पूर्णांक अतिप्रवाह में अपरिभाषित व्यवहार होता है, भले ही अतिप्रवाहित मूल्य हो या न पढ़ा हो।

हो सकता है कि आपके उपयोग-मामले में, आप इसे मोड़कर, पहले पुनरावृत्ति को लूप से बाहर निकाल सकें

int result = 0;
int factor = 1;
for (int n = 0; n < 10; ++n) {
    result += n + factor;
    factor *= 10;
}
// factor "is" 10^10 > INT_MAX, UB

इस मामले में

int factor = 1;
int result = 0 + factor; // first iteration
for (int n = 1; n < 10; ++n) {
    factor *= 10;
    result += n + factor;
}
// factor is 10^9 < INT_MAX

ऑप्टिमाइज़ेशन सक्षम होने के साथ, कंपाइलर दूसरे लूप को एक सशर्त कूद में अनियंत्रित कर सकता है।


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

निष्पक्ष अवलोकन, मैंने अपना उत्तर सही कर लिया है।
elbrunovsky

या अधिक बस, अंतिम पुनरावृत्ति को छीलें और मृतकों को हटा देंfactor *= 10;
पीटर कॉर्ड्स

9

यह यूबी है; ISO C ++ में पूरे कार्यक्रम का संपूर्ण व्यवहार एक निष्पादन के लिए पूरी तरह से अनिर्दिष्ट है जो अंततः यूबी को हिट करता है। क्लासिक उदाहरण सी ++ मानक देखभाल के रूप में दूर है, यह राक्षसों को आपकी नाक से बाहर उड़ सकता है। (मैं एक कार्यान्वयन का उपयोग करने के खिलाफ सलाह देता हूं जहां नाक राक्षस एक वास्तविक संभावना है)। अधिक विवरण के लिए अन्य उत्तर देखें।

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

यह भी देखें कि हर सी प्रोग्रामर को अपरिभाषित व्यवहार (LLVM ब्लॉग) के बारे में क्या जानना चाहिए । जैसा कि वहां बताया गया है, हस्ताक्षरित-अतिप्रवाह UB कंपाइलरों को यह साबित करने देता है कि for(... i <= n ...)लूप अनन्त लूप नहीं हैं, यहां तक ​​कि अज्ञात के लिए भी n। यह उन्हें साइन-एक्सटेंशन को रिड्यूस करने के बजाय पॉइंटर काउंटर से पॉइंटर चौड़ाई तक "प्रमोट" करने की सुविधा भी देता है। (तो उस स्थिति में UB का परिणाम किसी सरणी के निम्न 64k या 4G तत्वों तक पहुंच से बाहर हो सकता है, यदि आप iइसकी मूल्य सीमा में हस्ताक्षरित रैपिंग की उम्मीद कर रहे थे ।)

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


संभवत: सबसे कुशल समाधान अंतिम चलना को मैन्युअल रूप से छीलना है ताकि अनावश्यक factor*=10रूप से बचा जा सके।

int result = 0;
int factor = 1;
for (... i < n-1) {   // stop 1 iteration early
    result = ...
    factor *= 10;
}
 result = ...      // another copy of the loop body, using the last factor
 //   factor *= 10;    // and optimize away this dead operation.
return result;

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

यदि आप इसे हस्ताक्षरित प्रकारों के साथ उपयोग करते हैं, तो भी यह ठीक है , खासकर यदि आपका अहस्ताक्षरित-> हस्ताक्षरित रूपांतरण कभी भी अधिक नहीं होता है।

बिना हस्ताक्षर किए और 2 के पूरक के बीच रूपांतरण मुफ्त है (सभी मूल्यों के लिए एक ही बिट-पैटर्न); modulo int के लिए रैपिंग -> C ++ मानक द्वारा निर्दिष्ट अहस्ताक्षरित किसी के पूरक या संकेत / परिमाण के विपरीत, केवल एक ही बिट-पैटर्न का उपयोग करने के लिए सरल करता है।

और अहस्ताक्षरित-> हस्ताक्षरित समान रूप से तुच्छ है, हालांकि यह कार्यान्वयन-परिभाषित मूल्यों से बड़ा है INT_MAX। यदि आप अंतिम पुनरावृत्ति से विशाल अहस्ताक्षरित परिणाम का उपयोग नहीं कर रहे हैं , तो आपको चिंता करने की कोई बात नहीं है। लेकिन अगर आप हैं, तो क्या यह अहस्ताक्षरित से हस्ताक्षरित अपरिभाषित से रूपांतरण है? । मूल्य-रहित-फिट मामला कार्यान्वयन-परिभाषित है , जिसका अर्थ है कि कार्यान्वयन को कुछ व्यवहार चुनना होगा ; sane वाले सिर्फ अहस्ताक्षरित बिट पैटर्न को काटते हैं और इसे हस्ताक्षरित के रूप में उपयोग करते हैं, क्योंकि जो इन-रेंज के लिए काम करता है वह बिना किसी अतिरिक्त कार्य के समान है। और यह निश्चित रूप से यूबी नहीं है। तो बड़े अहस्ताक्षरित मान नकारात्मक हस्ताक्षरित पूर्णांक बन सकते हैं। उदाहरण के बाद int x = u; gcc और clang दूर का अनुकूलन नहीं करते हैंx>=0हमेशा सत्य के रूप में, बिना भी -fwrapv, क्योंकि उन्होंने व्यवहार को परिभाषित किया।


2
मैं यहाँ नीचे नहीं समझ सकता हूँ। मैं ज्यादातर अंतिम चलना छीलने के बारे में पोस्ट करना चाहता था। लेकिन अभी भी इस सवाल का जवाब देने के लिए, मैंने कुछ बिंदुओं को एक साथ फेंक दिया कि कैसे यूबी को टटोलना है। अधिक विवरण के लिए अन्य उत्तर देखें।
पीटर कॉर्ड्स

5

यदि आप लूप के बजाय कुछ अतिरिक्त असेंबली निर्देशों को सहन कर सकते हैं

int factor = 1;
for (int j = 0; j < n; ++j) {
    ...
    factor *= 10;
}

तुम लिख सकते हो:

int factor = 0;
for (...) {
    factor = 10 * factor + !factor;
    ...
}

आखिरी गुणा से बचने के लिए। !factorएक शाखा शुरू नहीं करेगा:

    xor     ebx, ebx
L1:                       
    xor     eax, eax              
    test    ebx, ebx              
    lea     edx, [rbx+rbx*4]      
    sete    al    
    add     ebp, 1                
    lea     ebx, [rax+rdx*2]      
    mov     edi, ebx              
    call    consume(int)          
    cmp     r12d, ebp             
    jne     .L1                   

यह कोड

int factor = 0;
for (...) {
    factor = factor ? 10 * factor : 1;
    ...
}

अनुकूलन के बाद शाखा रहित विधानसभा में भी परिणाम:

    mov     ebx, 1
    jmp     .L1                   
.L2:                               
    lea     ebx, [rbx+rbx*4]       
    add     ebx, ebx
.L1:
    mov     edi, ebx
    add     ebp, 1
    call    consume(int)
    cmp     r12d, ebp
    jne     .L2

(जीसीसी 8.3.0 के साथ संकलित -O3)


1
जब तक लूप शरीर बड़ा नहीं होता है, तब तक केवल अंतिम चलना छीलने के लिए सरल। यह एक चतुर हैक है, लेकिन लूप-आधारित निर्भरता श्रृंखला की विलंबता को factorथोड़ा बढ़ाता है । या नहीं: जब यह 2x ए के लिए संकलित यह सिर्फ ए + जोड़ें के रूप में कुशल के रूप में करने के लिए के बारे में है f *= 10के रूप में f*5*2, के साथ testपहले से छुपा विलंबता LEA। लेकिन यह लूप के अंदर अतिरिक्त खर्चे का खर्च करता है इसलिए नीचे की ओर एक संभावित थ्रूपुट (या कम से कम हाइपरथ्रेडिंग-फ्रेंडली इश्यू) है
पीटर कॉर्ड

4

आपने यह नहीं दिखाया कि forकथन के कोष्ठक में क्या है , लेकिन मैं यह मानने जा रहा हूँ कि यह कुछ इस तरह है:

for (int n = 0; n < 10; ++n) {
    result = ...
    factor *= 10;
}

आप बस शरीर में काउंटर वृद्धि और लूप समाप्ति की जांच कर सकते हैं:

for (int n = 0; ; ) {
    result = ...
    if (++n >= 10) break;
    factor *= 10;
}

लूप में विधानसभा निर्देशों की संख्या समान रहेगी।

आंद्रेई अलेक्जेंड्रेस्कु की प्रस्तुति "स्पीड इज़ फाउंड इन द माइंड्स ऑफ पीपल" से प्रेरित है।


2

फ़ंक्शन पर विचार करें:

unsigned mul_mod_65536(unsigned short a, unsigned short b)
{
  return (a*b) & 0xFFFFu;
}

प्रकाशित दलील के अनुसार, मानक के लेखकों की उम्मीद है कि अगर यह समारोह (जैसे) 0xC000 और 0xC000 के तर्क के साथ एक आम 32-बिट कंप्यूटर, पर लागू किए गए ऑपरेंड को बढ़ावा देने *के लिए signed intगणना -0x10000000 उपज के लिए कारण होगा , जो जब परिवर्तित करने के unsignedलिए उपज होगा 0x90000000u- वही जवाब के रूप में अगर वे को unsigned shortबढ़ावा दिया था unsigned। फिर भी, जीसीसी कभी-कभी उस फ़ंक्शन को उन तरीकों से अनुकूलित करेगा जो अतिप्रवाह होने पर निरर्थक व्यवहार करेंगे। कोई भी कोड जहां इनपुट के कुछ संयोजन के कारण एक अतिप्रवाह हो सकता है, -fwrapvविकल्प के साथ संसाधित किया जाना चाहिए जब तक कि यह जानबूझकर-विकृत इनपुट के रचनाकारों को उनके चयन के मनमाने कोड को निष्पादित करने की अनुमति देने के लिए स्वीकार्य नहीं होगा।


1

ऐसा क्यों नहीं:

int result = 0;
int factor = 10;
for (...) {
    factor *= 10;
    result = ...
}
return result;

यही कारण है कि नहीं चलता है ...के लिए पाश शरीर factor = 1या factor = 10केवल 100 और अधिक है। आपको पहले पुनरावृत्ति को छीलना होगा औरfactor = 1 यदि आप इसे काम करना चाहते हैं, तब भी शुरू करें।
पीटर कॉर्ड्स

1

अनिर्धारित व्यवहार के कई अलग-अलग चेहरे हैं, और जो स्वीकार्य है वह उपयोग पर निर्भर करता है।

टाइट इनर-लूप जो वास्तविक समय के ग्राफिक्स एप्लिकेशन में कुल सीपीयू समय के एक बड़े हिस्से की खपत करता है

वह, अपने आप में, एक असामान्य बात है, लेकिन जैसा कि यह हो सकता है ... यदि यह वास्तव में मामला है, तो यूबी सबसे अधिक "स्वीकार्य, स्वीकार्य" दायरे में है । ग्राफिक्स प्रोग्रामिंग हैक और बदसूरत सामान के लिए कुख्यात है। जब तक यह "काम करता है" और एक फ्रेम का उत्पादन करने में 16.6ms से अधिक समय नहीं लगता है, आमतौर पर, कोई भी परवाह नहीं करता है। लेकिन फिर भी, इस बात से अवगत रहें कि यूबी को लागू करने का क्या मतलब है।

सबसे पहले, वहाँ मानक है। उस दृष्टिकोण से, चर्चा के लिए कुछ भी नहीं है और औचित्य का कोई तरीका नहीं है, आपका कोड बस अमान्य है। वहाँ कोई ifs या whens हैं, यह सिर्फ एक वैध कोड नहीं है। आप यह भी कह सकते हैं कि आपके नज़रिए से मध्य-उँगलियाँ हैं, और 95-99% समय आप वैसे भी जाने के लिए अच्छा होगा।

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

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

(और अंत में, बेशक कोड ऑडिट है, यदि आपको अशुभ होने पर ऑडिटर के साथ चर्चा करने में अपना समय बर्बाद करना पड़ सकता है।)

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