C ++ में 'अपरिभाषित व्यवहार' (UB) और C # या Java जैसी अन्य भाषाएँ क्यों नहीं हैं?


50

यह स्टैक ओवरफ्लो पोस्ट उन स्थितियों की काफी व्यापक सूची को सूचीबद्ध करता है जहां C / C ++ भाषा विनिर्देश 'अपरिभाषित व्यवहार' घोषित करता है। हालाँकि, मैं यह समझना चाहता हूं कि C # या Java जैसी अन्य आधुनिक भाषाओं में 'अपरिभाषित व्यवहार' की अवधारणा क्यों नहीं है। क्या इसका मतलब है, संकलक डिजाइनर सभी संभावित परिदृश्यों (सी # और जावा) को नियंत्रित कर सकता है या नहीं (सी और सी ++)?




3
और फिर भी यह SO पोस्ट जावा युक्ति में भी अपरिभाषित व्यवहार को संदर्भित करता है!
gbjbaanb

"C ++ के पास 'अनिर्धारित व्यवहार' क्यों है" दुर्भाग्य से, यह उन सवालों में से एक है जो उद्देश्यपूर्ण रूप से उत्तर देने में मुश्किल है, बयान से परे "क्योंकि, कारणों से एक्स, वाई और / या जेड (जिनमें से सभी हो सकते हैं nullptr: नहीं) एक व्यक्ति ने व्यवहार को परिभाषित करने और / या एक प्रस्तावित विनिर्देश को अपनाने के लिए परेशान किया "। : c
code_dredd

मैं आधार को चुनौती दूंगा। कम से कम C # में "असुरक्षित" कोड है। Microsoft लिखता है "एक अर्थ में, असुरक्षित कोड लिखना एक C # प्रोग्राम के भीतर C कोड लिखना बहुत पसंद है" और उदाहरण देता है कि कोई ऐसा क्यों करना चाहेगा: हार्डवेयर या ओएस तक पहुंचने के लिए और गति के लिए। यह वही है जो सी के लिए आविष्कार किया गया था (नरक, उन्होंने सी में ओएस लिखा है!), इसलिए आपके पास यह है।
पीटर -

जवाबों:


72

अपरिभाषित व्यवहार उन चीजों में से एक है जिन्हें केवल पूर्वव्यापी में एक बहुत बुरे विचार के रूप में मान्यता दी गई थी।

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

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

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

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

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


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

13
जवाब का मुख्य हिस्सा वास्तव में मेरे लिए ठोस नहीं है। मेरा मतलब है, मूल रूप से एक फ़ंक्शन लिखना असंभव है int32_t add(int32_t x, int32_t y)जो सी ++ में सुरक्षित रूप से दो नंबर (जैसे ) जोड़ता है। उस एक के आसपास सामान्य तर्क दक्षता से संबंधित होते हैं, लेकिन अक्सर कुछ पोर्टेबिलिटी के तर्क (जैसे "एक बार लिखें, चलाएं ... उस मंच पर जहां आपने इसे लिखा था ... और कहीं नहीं ;-)") के साथ मिलाया। मोटे तौर पर, एक तर्क इसलिए हो सकता है: कुछ चीजें अपरिभाषित हैं क्योंकि आप नहीं जानते कि आप 16bit के माइक्रोकंटोलर पर हैं या 64 बिट सर्वर (एक कमजोर, लेकिन अभी भी एक तर्क)
मार्को 13

12
@ मार्को 13 सहमत - और "परिभाषित व्यवहार" से छुटकारा पाने के लिए कुछ "परिभाषित व्यवहार" करके, लेकिन जरूरी नहीं कि उपयोगकर्ता चाहता था और बिना किसी चेतावनी के जब यह "अपरिभाषित व्यवहार" के बजाय "कोड-वकील गेम आईएमओ खेल रहा है"। ।
एलेफ़ेज़रो

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

34
"अपरिभाषित व्यवहार उन चीजों में से एक है जिन्हें केवल पूर्वव्यापी में एक बहुत बुरे विचार के रूप में मान्यता दी गई थी।" कि आपकी राय। कई (स्वयं शामिल) इसे साझा नहीं करते हैं।
मोनिका

103

मूलतः क्योंकि जावा और इसी तरह की भाषाओं के डिजाइनर अपनी भाषा में अपरिभाषित व्यवहार नहीं चाहते थे। यह एक व्यापार बंद था - अपरिभाषित व्यवहार की अनुमति देने से प्रदर्शन में सुधार करने की क्षमता होती है, लेकिन भाषा डिजाइनरों ने सुरक्षा और भविष्यवाणी को प्राथमिकता दी।

उदाहरण के लिए, यदि आप C में एक सरणी आवंटित करते हैं, तो डेटा अपरिभाषित है। जावा में, सभी बाइट्स को 0 (या कुछ अन्य निर्दिष्ट मूल्य) पर आरंभीकृत किया जाना चाहिए। इसका मतलब यह है कि रनटाइम को सरणी (O (n) ऑपरेशन) के ऊपर से गुजरना होगा, जबकि C एक पल में आवंटन का प्रदर्शन कर सकता है। तो ऐसे ऑपरेशन के लिए C हमेशा तेज रहेगा।

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


19
HLL दुविधा की उत्कृष्ट प्रस्तुति: सुरक्षा और उपयोग में आसानी बनाम प्रदर्शन। कोई चांदी की गोली नहीं है: प्रत्येक पक्ष के लिए उपयोग के मामले हैं।
क्रिस्टोफ

5
@Christophe निष्पक्ष होना, यूबी को सी और सी ++ की तरह पूरी तरह से निर्विरोध होने की तुलना में एक समस्या के लिए बहुत बेहतर दृष्टिकोण हैं। आपके लिए एक सुरक्षित, प्रबंधित भाषा हो सकती है, जहाँ आप बची हुई हैट को असुरक्षित क्षेत्र में रख सकते हैं, जहाँ आप लाभकारी हैं। टीबीएच, यह वास्तव में सिर्फ मेरे सी / सी ++ प्रोग्राम को एक ध्वज के साथ संकलित करने में सक्षम होगा, जो कहता है कि "आपको जो भी महंगा रनटाइम मशीनरी की आवश्यकता है उसे डालें, मुझे परवाह नहीं है, लेकिन मुझे बस यूबी के बारे में बताएं जो होता है । "
सिकंदर

4
एक डेटा संरचना का एक अच्छा उदाहरण जो जानबूझकर अनधिकृत स्थानों को पढ़ता है वह है ब्रिग्स और टॉरगॉन का विरल सेट प्रतिनिधित्व (जैसे कि कोडिंगप्लेग्राउंड.ब्लॉगस्पॉट.com/2009/03/… ) देखें ) इस तरह के सेट का प्रारंभ C में O (1) है, लेकिन O ( n) जावा की मजबूर इनिशियलाइज़ेशन के साथ।
आर्क डी। रोबिसन

9
हालांकि यह सच है कि डेटा के प्रारंभिककरण के कारण टूटे हुए प्रोग्राम बहुत अधिक पूर्वानुमानित हो जाते हैं, यह इच्छित व्यवहार की गारंटी नहीं देता है: यदि एल्गोरिथ्म ने अनुमानित रूप से प्रारंभिक शून्य को गलत तरीके से पढ़ते हुए सार्थक डेटा को पढ़ने की अपेक्षा की है, तो यह एक बग के रूप में बहुत अधिक बग है। कुछ कचरा पढ़ो। C / C ++ प्रोग्राम के साथ, इस तरह की बग प्रक्रिया के तहत valgrindचलकर दिखाई देगी, जो बिल्कुल वही दिखाती है जहां असमान मूल्य का उपयोग किया गया था। आप valgrindजावा कोड का उपयोग नहीं कर सकते क्योंकि रनटाइम इनिशियलाइज़ेशन करता है, जिससे valgrindचेक बेकार हो जाता है।
सेमीस्टर

5
@cmaster यही कारण है कि C # कंपाइलर आपको अनइंस्टॉल किए गए लोकल से पढ़ने की अनुमति नहीं देता है। रनटाइम चेक की कोई आवश्यकता नहीं, आरंभीकरण की आवश्यकता नहीं, बस संकलन-समय विश्लेषण। यह अभी भी एक व्यापार-बंद है, हालांकि - कुछ ऐसे मामले हैं जहां आपके पास संभावित निरंकुश स्थानीय लोगों के आसपास शाखाकरण को संभालने का एक अच्छा तरीका नहीं है। व्यवहार में, मुझे कोई भी ऐसा मामला नहीं मिला जहां यह पहली बार में खराब डिजाइन नहीं था और जटिल शाखाओं में बँटने से बचने के लिए कोड को पुनर्विचार करने के माध्यम से बेहतर हल किया गया था (जो कि मनुष्यों के लिए कठिन है), लेकिन यह कम से कम संभव है।
लुआं

42

अपरिभाषित व्यवहार, कुछ सीमा या अन्य स्थितियों में कुछ विषम या अप्रत्याशित (या सामान्य) करने के लिए संकलक अक्षांश देकर महत्वपूर्ण अनुकूलन को सक्षम करता है।

Http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html देखें

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


पूर्णांक ओवरफ़्लो पर हस्ताक्षर किए गए: यदि 'int' प्रकार (उदाहरण के लिए) ओवरफ़्लो पर अंकगणित होता है, तो परिणाम अपरिभाषित होता है। एक उदाहरण यह है कि "INT_MAX + 1" को INT_MIN होने की गारंटी नहीं है। यह व्यवहार कुछ वर्गों के अनुकूलन को सक्षम करता है जो कुछ कोड के लिए महत्वपूर्ण हैं। उदाहरण के लिए, यह जानकर कि INT_MAX + 1 अपरिभाषित है, "X + 1> X" को "सत्य" के रूप में अनुकूलित करने की अनुमति देता है। गुणन को जानकर "ओवरफ्लो" नहीं किया जा सकता है (क्योंकि ऐसा करना अपरिभाषित होगा) "एक्स * 2/2" को "एक्स" के लिए अनुकूलित करने की अनुमति देता है। जबकि ये तुच्छ लग सकते हैं, इन प्रकार की चीजें आमतौर पर inlining और मैक्रो के विस्तार से उजागर होती हैं। एक और अधिक महत्वपूर्ण अनुकूलन जो यह अनुमति देता है वह इस तरह के "<=" छोरों के लिए है:

for (i = 0; i <= N; ++i) { ... }

इस लूप में, कंपाइलर मान सकता है कि लूप बिल्कुल N + 1 बार इफर्ट करेगा अगर "i" ओवरफ्लो पर अपरिभाषित है, जो लूप ऑप्टिमाइजेशन की एक विस्तृत श्रृंखला को किक करने की अनुमति देता है। दूसरी तरफ, यदि वैरिएबल को परिभाषित किया गया है। ओवरफ्लो पर चारों ओर लपेटो, तब कंपाइलर को यह मान लेना चाहिए कि लूप संभवतः अनंत है (जो होता है यदि N INT_MAX है) - जो तब इन महत्वपूर्ण लूप ऑप्टिमाइज़ेशन को निष्क्रिय कर देता है। यह विशेष रूप से 64-बिट प्लेटफार्मों को प्रभावित करता है क्योंकि बहुत सारे कोड इंडक्शन वेरिएबल्स के रूप में "int" का उपयोग करते हैं।


27
बेशक, हस्ताक्षरित-पूर्णांक ओवरफ़्लो अपरिभाषित होने का वास्तविक कारण यह है कि जब सी विकसित किया गया था, तो उपयोग में हस्ताक्षरित पूर्णांक के कम से कम तीन अलग-अलग प्रतिनिधित्व थे (एक-पूरक, दो-पूरक, साइन-परिमाण, और शायद बाइनरी) , और प्रत्येक INT_MAX + 1 के लिए एक अलग परिणाम देता है। अतिप्रवाहित अपरिभाषित परमिट a + bको add b aहर स्थिति में मूल अनुदेश के लिए संकलित करने के बजाय, संभावित रूप से संकलित किए गए पूर्णांक अंकगणित के कुछ अन्य रूप का अनुकरण करने के लिए आवश्यक है।
मार्क

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

5
@ सुपरकार्ट अपरिभाषित व्यवहार से बचने का एक और कारण है जो हाल की भाषाओं में अधिक सामान्य है - प्रोग्रामर का समय सीपीयू समय की तुलना में बहुत अधिक है। सीबी को यूबी के लिए धन्यवाद करने की अनुमति दी गई है, आधुनिक डेस्कटॉप कंप्यूटरों पर अनिवार्य रूप से व्यर्थ हैं, और कोड के बारे में तर्क बहुत कठिन बनाते हैं (सुरक्षा निहितार्थ का उल्लेख नहीं करने के लिए)। यहां तक ​​कि प्रदर्शन महत्वपूर्ण कोड में, आप उच्च-स्तरीय अनुकूलन से लाभ उठा सकते हैं जो सी में करने के लिए कुछ हद तक कठिन (या बहुत कठिन) होगा I मेरे पास सी # में अपना स्वयं का सॉफ़्टवेयर 3 डी रेंडरर है, और उदाहरण के लिए उपयोग करने में सक्षम होना एक HashSetअद्भुत है।
लुआं

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

@MSalters एक सरल और अच्छी तरह से अध्ययन किया गया समाधान है जो न तो अपरिभाषित व्यवहार या कार्यान्वयन परिभाषित व्यवहार है: नॉनडेर्मिनिस्टिक व्यवहार। यही है, आप कह सकते हैं " x << yप्रकार के कुछ वैध मूल्य का मूल्यांकन करता है int32_tलेकिन हम यह नहीं कहेंगे कि कौन सा"। यह कार्यान्वयनकर्ताओं को तेज़ समाधान का उपयोग करने की अनुमति देता है, लेकिन समय-यात्रा शैली के अनुकूलन की अनुमति देने वाले झूठे पूर्व शर्त के रूप में कार्य नहीं करता है क्योंकि नोंदेर्तिवाद इस एक ऑपरेशन के आउटपुट के लिए विवश है - कल्पना की गारंटी है कि मेमोरी, वाष्पशील चर, आदि दृष्टिगत रूप से प्रभावित नहीं हैं। अभिव्यक्ति मूल्यांकन द्वारा। ...
मारियो कार्नेइरो

20

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

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


तो क्या आप कह रहे हैं, बैकवर्ड कम्पैटिबिलिटी ही एकमात्र कारण है कि C और C ++ अपरिभाषित व्यवहारों से बाहर नहीं निकल रहे हैं?
सिसिर

3
यह निश्चित रूप से बड़े लोगों में से एक है, @ शिशिर। यहां तक कि अनुभवी प्रोग्रामर के बीच में, आप आश्चर्य होगा कितना सामान है कि नहीं तोड़ चाहिए करता तोड़ने जब एक संकलक का तरीका बदलता है अपरिभाषित व्यवहार संभालती है। (प्रकरण बिंदु में, वहाँ अराजकता का एक सा जब जीसीसी बाहर के अनुकूलन शुरू कर दिया था, "है thisएक समय पहले की जाँच करता है, इस आधार पर कि पर अशक्त?" thisकिया जा रहा है nullptrवास्तव में ऐसा कभी नहीं कर सकते हैं यूबी है, और इस तरह।)
जस्टिन समय 2 को पुन: स्थापित मोनिका

9
@ शिशिर, एक और बड़ी गति है। सी के शुरुआती दिनों में, हार्डवेयर आज की तुलना में कहीं अधिक विषम था। केवल यह निर्दिष्ट नहीं करके कि जब आप INT_MAX में 1 जोड़ते हैं, तो आप आर्किटेक्चर के लिए सबसे तेज गति से कंपाइलर को कर सकते हैं (जैसे कि एक-पूरक प्रणाली -INT_MAX का उत्पादन करेगी, जबकि दो-पूरक प्रणाली INTMMIN का उत्पादन करेगी)। इसी तरह, जब आप किसी सरणी के अंत में पढ़ते हैं, तो यह निर्दिष्ट नहीं करने से, आपके पास मेमोरी सुरक्षा के साथ एक प्रणाली हो सकती है कार्यक्रम को समाप्त कर सकते हैं, जबकि एक के बिना महंगे रनटाइम सीमा-जाँच को लागू करने की आवश्यकता नहीं होगी।
मार्क

14

JVM और .NET भाषाओं में यह आसान है:

  1. उन्हें सीधे हार्डवेयर के साथ काम करने में सक्षम नहीं होना चाहिए।
  2. उन्हें केवल आधुनिक डेस्कटॉप और सर्वर सिस्टम या यथोचित समान उपकरणों, या कम से कम उनके लिए डिज़ाइन किए गए उपकरणों के साथ काम करना होगा।
  3. वे सभी मेमोरी के लिए कचरा-संग्रह को लागू कर सकते हैं, और मजबूर प्रारंभिककरण, इस प्रकार सूचक-सुरक्षा प्राप्त कर सकते हैं।
  4. उन्हें एकल अभिनेता द्वारा निर्दिष्ट किया गया था, जिन्होंने एकल निर्णायक कार्यान्वयन भी प्रदान किया।
  5. उन्हें प्रदर्शन पर सुरक्षा का चयन करने के लिए मिलता है।

हालांकि विकल्पों के लिए अच्छे अंक हैं:

  1. सिस्टम प्रोग्रामिंग एक पूरी तरह से अलग बॉलगेम है, और इसके बजाय एप्लिकेशन प्रोग्रामिंग के लिए अनपेक्षित रूप से अनुकूलन उचित है।
  2. बेशक, हर समय कम विदेशी हार्डवेयर है, लेकिन रहने के लिए छोटे एम्बेडेड सिस्टम यहां हैं।
  3. जीसी गैर-कवक संसाधनों के लिए बीमार है, और अच्छे प्रदर्शन के लिए बहुत अधिक स्थान का व्यापार करता है। और सबसे (लेकिन लगभग सभी नहीं) मजबूर प्रारंभिकताओं को दूर अनुकूलित किया जा सकता है।
  4. अधिक प्रतिस्पर्धा के फायदे हैं, लेकिन समितियों का मतलब है समझौता।
  5. उन सभी सीमा-जांचों को जोड़ दिया जाता है, भले ही अधिकांश को दूर अनुकूलित किया जा सकता है। शून्य पॉइंटर चेक ज्यादातर वर्चुअल पता स्थान के लिए शून्य ओवरहेड के लिए पहुंच में फंसने से किया जा सकता है, हालांकि अनुकूलन अभी भी बाधित है।

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


3
वास्तव में। मैं अपनी नौकरी के लिए C # में प्रोग्राम करता हूं। हर बार थोड़ी देर में मैं एक असुरक्षित हथौड़ों ( unsafeकीवर्ड या विशेषताओं में System.Runtime.InteropServices) के लिए पहुंचता हूं । इस प्रोग्राम को कुछ प्रोग्रामर्स के पास रख कर, जो जानते हैं कि अनवांटेड सामान को कैसे डिबग करें और फिर से इसे कम से कम प्रैक्टिकल के रूप में देखें, हम मुद्दों को कम करते हैं। यह पिछले प्रदर्शन-संबंधित असुरक्षित-हथौड़ा के बाद से 10 साल से अधिक समय हो गया है, लेकिन कभी-कभी आप इसे करते हैं, क्योंकि इसका शाब्दिक कोई अन्य समाधान नहीं है।
जोशुआ

19
मैं अक्सर एनालॉग उपकरणों से एक प्लेटफ़ॉर्म पर काम करता हूं, जहां sizeof (char) == sizeof (लघु) == sizeof (int) == sizeof (फ्लोट) == 1. यह संतृप्त जोड़ भी करता है (इसलिए INT_MAX + 1 = - INT_MAX) , और सी के बारे में अच्छी बात यह है कि मैं एक अनुरूप संकलक हो सकता है जो उचित कोड उत्पन्न करता है। यदि भाषा में कहा गया है कि टीडोस पूरक रैप के साथ पूरक है तो हर जोड़ एक परीक्षण और एक शाखा के साथ समाप्त हो जाएगा, एक डीएसपी केंद्रित भाग में एक गैर स्टार्टर के कुछ। यह एक वर्तमान उत्पादन हिस्सा है।
डेन मिल्स

5
@BenVoigt हम में से कुछ एक ऐसी दुनिया में रहते हैं जहाँ एक छोटा कंप्यूटर शायद कोड स्पेस का 4k है, एक फिक्स्ड 8 लेवल कॉल / रिटर्न स्टैक, 64 बाइट्स RAM, 1MHz क्लॉक और इसकी कीमत $ 1,000 में <$ 0.20 है। एक आधुनिक मोबाइल फोन सभी इरादों और उद्देश्यों के लिए बहुत अधिक असीमित भंडारण के साथ एक छोटा पीसी है, और पीसी के रूप में बहुत अधिक व्यवहार किया जा सकता है। सारी दुनिया बहुसंख्‍यक नहीं है और इसमें कठोर रीयल टाइम बाधाओं का अभाव है।
दान मिल्स

2
@DanMills: आर्म कॉर्टेक्स ए प्रोसेसर के साथ यहां आधुनिक मोबाइल फोन के बारे में बात नहीं करना, "फीचर फोन" लगभग 2002 की बात करना। हां SRAM का 192kB 64 बाइट्स (जो "छोटा" नहीं है लेकिन "छोटे") से बहुत अधिक है, लेकिन 192kB को भी 30 वर्षों के लिए "आधुनिक" डेस्कटॉप या सर्वर नहीं कहा गया है। इसके अलावा इन दिनों 20 सेंट आपको MSP430 मिलेगा जिसमें SRAM के 64 बाइट्स होंगे।
बेन वायगेट

2
@BenVoigt 192kB पिछले 30 वर्षों में एक डेस्कटॉप नहीं हो सकता है, लेकिन मैं आपको आश्वस्त कर सकता हूं कि यह पूरी तरह से वेब पृष्ठों की सेवा करने के लिए पर्याप्त है, जो मैं तर्क देता हूं कि शब्द की बहुत परिभाषा से ऐसा काम एक सर्वर बना देगा। तथ्य यह है कि एम्बेडेड अनुप्रयोगों के एक बहुत है कि अक्सर विन्यास वेब सर्वर शामिल के लिए राम की एक पूरी तरह से उचित (उदार, यहां तक ​​कि) राशि है। ज़रूर, मैं शायद इस पर अमेज़ॅन नहीं चला रहा हूं, लेकिन मैं बस ऐसे कोर पर आईओटी क्रैपवेयर के साथ फ्रिज को पूरा कर सकता हूं (समय और स्थान के साथ)। उसके लिए किसी को व्याख्या या JIT भाषाओं की आवश्यकता नहीं है!
डेन मिल्स

8

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

ऐसा इसलिए भी है क्योंकि किसी एक व्यवहार का चयन करना हार्डवेयर आर्किटेक्चर पर महंगा हो सकता है जो कि किसी अन्य विकल्प के प्रति पक्षपाती है - एंडियननेस स्पष्ट विकल्प है।


"बड़े आम भाजक" का शाब्दिक अर्थ क्या है? क्या आप सबसेट या सुपरसेट के बारे में बात कर रहे हैं? क्या आप वास्तव में आम में पर्याप्त कारक हैं? क्या यह कम से कम कई तरह का है या सबसे बड़ा सामान्य कारक है? यह हमारे लिए बहुत ही भ्रमित करने वाले रोबोट हैं जो सड़क के लिंगो, सिर्फ गणित नहीं बोलते हैं। :)
tchrist

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

2
मूल C एक आदमी द्वारा बनाया गया था। यह पहले से ही काफी यूबी था, डिजाइन द्वारा। सी निश्चित रूप से लोकप्रिय होते ही चीजें खराब हो गईं, लेकिन यूबी शुरुआत से ही वहां था। पास्कल और स्मॉलटाक में यूबी काफी कम था और इसे उसी समय विकसित किया गया था। C का मुख्य लाभ यह था कि इसे पोर्ट करना बेहद आसान था - सभी पोर्टेबिलिटी मुद्दों को एप्लिकेशन प्रोग्रामर को सौंप दिया गया था: P मैंने अपने (वर्चुअल) सीपीयू में एक साधारण सी कंपाइलर भी पोर्ट किया है; LISP या स्मॉलटॉक जैसा कुछ करने से कहीं अधिक प्रयास होता (हालांकि मेरे पास .NET रनटाइम के लिए एक सीमित प्रोटोटाइप था :)।
लुआं

@ लुआण: कि कर्निघन या रिची होगा? और नहीं, इसमें अपरिभाषित व्यवहार नहीं था। मुझे पता है, मेरे पास मेरी मेज पर मूल एटी एंड टी स्टैंकेल्ड कंपाइलर प्रलेखन है। कार्यान्वयन ने वही किया जो उसने किया। अनिर्दिष्ट और अपरिभाषित व्यवहार में कोई भेद नहीं था।
MSalters

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

6

वास्तविक कारण एक तरफ सी और सी ++ के बीच एक मूल अंतर के लिए नीचे आता है, और दूसरी तरफ जावा और सी # (केवल कुछ उदाहरणों के लिए)। ऐतिहासिक कारणों से, यहाँ पर चर्चा सी + + के बजाय सी के बारे में बात करती है, लेकिन (जैसा कि आप शायद पहले से ही जानते हैं) सी ++ सी का काफी प्रत्यक्ष वंशज है, इसलिए सी के बारे में जो कहता है वह सी ++ के समान ही लागू होता है।

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

इसे पूरा करने के लिए, सी को हार्डवेयर तक पहुंच के लगभग समान स्तर प्रदान करने की आवश्यकता थी जैसा कि विधानसभा की भाषा ने किया था। PDP-11 (एक उदाहरण के लिए) मैंने विशिष्ट पते के लिए I / O रजिस्टर किया। उदाहरण के लिए, आप यह जांचने के लिए एक मेमोरी लोकेशन पढ़ेंगे कि क्या सिस्टम कंसोल पर कोई कुंजी दबाई गई थी। उस स्थान पर एक बिट सेट किया गया था जब डेटा पढ़ने के लिए प्रतीक्षा की जा रही थी। फिर आप उस कुंजी के ASCII कोड को पुनः प्राप्त करने के लिए किसी अन्य निर्दिष्ट स्थान से एक बाइट पढ़ेंगे जिसे दबाया गया था।

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

ऐसे उपकरणों के लिए लेखन ड्राइवरों का समर्थन करने के लिए, सी ने आपको कुछ पूर्णांक प्रकार का उपयोग करके एक मनमाना स्थान निर्दिष्ट करने की अनुमति दी, इसे एक पॉइंटर में बदल दिया और स्मृति में उस स्थान को पढ़ा या लिखा।

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

मैं कुछ संभावनाएं देख सकता हूं जो छोड़ देता है:

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

इनमें से, 1 पर्याप्त रूप से पूर्व-निर्धारित लगता है कि यह शायद ही आगे चर्चा के लायक है। 2 मूल रूप से भाषा के मूल इरादे को दूर कर रहा है। तीसरे विकल्प के रूप में अनिवार्य रूप से केवल एक ही वे सभी पर उचित विचार कर सकते हैं छोड़ देता है।

एक अन्य बिंदु जो काफी बार आता है वह पूर्णांक प्रकारों का आकार है। सी "स्थिति" लेता intहै जो वास्तुकला द्वारा सुझाए गए प्राकृतिक आकार का होना चाहिए। इसलिए, अगर मैं 32-बिट वैक्स का प्रोग्रामिंग कर रहा हूं, तो intशायद 32 बिट्स होना चाहिए, लेकिन अगर मैं 36-बिट यूनीवैक प्रोग्रामिंग कर रहा हूं, intतो शायद 36 बिट्स (और इसी तरह) होना चाहिए। यह केवल 36 प्रकार के कंप्यूटर के लिए एक ऑपरेटिंग सिस्टम लिखने के लिए उचित नहीं है (और यह भी संभव नहीं हो सकता है) केवल उन प्रकारों का उपयोग करके जो 8 बिट के गुणकों के आकार की गारंटी हैं। शायद मैं सिर्फ सतही हो रहा हूं, लेकिन यह मुझे लगता है कि अगर मैं 36-बिट मशीन के लिए एक ओएस लिख रहा था, तो मैं शायद एक ऐसी भाषा का उपयोग करना चाहता हूं जो 36-बिट प्रकार का समर्थन करती है।

भाषा के दृष्टिकोण से, यह अभी भी अपरिभाषित व्यवहार की ओर जाता है। यदि मैं सबसे बड़ा मूल्य लेता हूं जो 32 बिट्स में फिट होगा, तो 1 जोड़ने पर क्या होगा? विशिष्ट 32-बिट हार्डवेयर पर, यह रोल करने जा रहा है (या संभवतः किसी प्रकार का हार्डवेयर दोष फेंक सकता है)। दूसरी ओर, अगर यह 36-बिट हार्डवेयर पर चल रहा है, तो यह बस ... एक जोड़ देगा। यदि भाषा ऑपरेटिंग सिस्टम लिखने में सहायता करने वाली है, तो आप व्यवहार की गारंटी नहीं दे सकते हैं - आपको बस दोनों प्रकारों के आकार और ओवरफ्लो के व्यवहार को एक से दूसरे में भिन्न होने की अनुमति देनी होगी।

Java और C # उस सब को नजरअंदाज कर सकते हैं। वे लेखन ऑपरेटिंग सिस्टम का समर्थन करने के इरादे से नहीं हैं। उनके साथ, आपके पास कुछ विकल्प हैं। एक हार्डवेयर समर्थन बनाने के लिए है कि वे क्या मांग करते हैं - चूंकि वे 8, 16, 32 और 64 बिट्स प्रकार की मांग करते हैं, बस उन हार्डवेयर का निर्माण करते हैं जो हर आकार का समर्थन करते हैं। अन्य स्पष्ट संभावना भाषा के लिए केवल अन्य सॉफ़्टवेयर के शीर्ष पर चलने के लिए है जो वे परिवेश प्रदान करते हैं, जो चाहे अंतर्निहित हार्डवेयर चाहे।

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

सारांश

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


4

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

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


मुझे लगता है कि आपने यहां कुछ महत्वपूर्ण वर्णन किया है, लेकिन यह मुझे बचता है। क्या आप अपना उत्तर स्पष्ट कर सकते हैं? विशेष रूप से दूसरा पैराग्राफ: यह कहता है कि अब स्थितियां और पहले की स्थितियां अलग हैं, लेकिन मुझे यह नहीं मिलता है; वास्तव में क्या बदला? इसके अलावा, "रास्ता" अब पहले की तुलना में अलग है; शायद यह भी समझाएं?
एंथोलीग

4
लगता है कि अनिर्दिष्ट व्यवहार के साथ सभी अपरिभाषित व्यवहार को बदलने के लिए आपका अभियान लगता है या कुछ और विवश अभी भी मजबूत हो रहा है।
डेडुप्लिकेटर

1
@anatolyg: यदि आप पहले से प्रकाशित नहीं हुए हैं, तो C Cationale दस्तावेज़ (Google में C99 Rationale टाइप करें) पढ़ें। पृष्ठ 11 लाइनें 23-29 "मार्केटप्लेस" के बारे में बात करते हैं, और पेज 13 लाइनें 5-8 के बारे में बात करते हैं कि पोर्टेबिलिटी के संबंध में क्या इरादा है। आपको क्या लगता है कि एक वाणिज्यिक संकलक कंपनी में एक बॉस क्या प्रतिक्रिया देगा यदि एक संकलक लेखक ने प्रोग्रामर को बताया कि शिकायतकर्ता ने कोड को तोड़ दिया है कि हर दूसरे संकलक ने उपयोगी रूप से संभाला है कि उनका कोड "टूटा हुआ" है क्योंकि यह मानक द्वारा परिभाषित नहीं क्रिया करता है, और इसका समर्थन करने से इनकार कर दिया क्योंकि यह जारी रहेगा को बढ़ावा देगा ...
सुपरकैट

1
... ऐसे निर्माणों का उपयोग? ऐसा दृष्टिकोण क्लैंग और जीसीसी के समर्थन बोर्डों पर स्पष्ट रूप से स्पष्ट है, और आंतरिक भाषा के विकास को बाधित करने के लिए कार्य किया है जो टूटी भाषा जीसीसी और क्लैंग का समर्थन करने की तुलना में कहीं अधिक आसानी से और सुरक्षित रूप से अनुकूलन की सुविधा प्रदान कर सकता है।
सुपरकैट

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

3

C ++ और c दोनों में वर्णनात्मक मानक (आईएसओ संस्करण, वैसे भी) हैं।

जो केवल यह समझाने के लिए मौजूद हैं कि भाषा कैसे काम करती है, और भाषा क्या है, इसके बारे में एक ही संदर्भ प्रदान करती है। आमतौर पर, कंपाइलर विक्रेताओं, और पुस्तकालय लेखकों, मुख्य आईएसओ मानक में शामिल होने के तरीके और कुछ सुझावों का नेतृत्व करते हैं।

जावा और सी # (या विजुअल सी #, जो मुझे लगता है कि आपका मतलब है) में प्रिस्क्रिपटिव मानक हैं। वे आपको बताते हैं कि समय से पहले भाषा में क्या है, यह कैसे काम करता है, और अनुमति व्यवहार को क्या माना जाता है।

उससे अधिक महत्वपूर्ण, जावा का वास्तव में ओपन-जेडडीके में "संदर्भ कार्यान्वयन" है। (मुझे लगता है कि रोसलिन विजुअल C # संदर्भ कार्यान्वयन के रूप में गिना जाता है, लेकिन उसके लिए कोई स्रोत नहीं खोज सका।

जावा के मामले में, यदि मानक में कोई अस्पष्टता है, और ओपन-जेडडीके यह एक निश्चित तरीका है। ओपन-जेडडीके जिस तरह से यह मानक है।


स्थिति इससे भी बदतर है: मुझे नहीं लगता कि समिति ने कभी इस बारे में सर्वसम्मति हासिल की है कि क्या यह वर्णनात्मक या प्रिस्क्रिप्टिव माना जाता है।
सुपरकैट

1

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

उदाहरण के लिए, हस्ताक्षर किए गए ओवरफ्लो सी में अपरिभाषित व्यवहार हैं। व्यवहार में कंपाइलर को सीपीयू को निष्पादित करने के लिए एक सरल हस्ताक्षरित अतिरिक्त ऑपकोड उत्पन्न करने की उम्मीद थी, और व्यवहार वह होगा जो विशेष रूप से सीपीयू ने किया था।

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

यही कारण है कि सी में अपरिभाषित व्यवहार का बहुत कारण है, और intसिस्टम के बीच भिन्नता के आकार जैसी चीजें क्यों होती हैं । Intवास्तुकला पर निर्भर है और आम तौर पर सबसे तेज, सबसे कुशल डेटा प्रकार है कि एक से बड़ा है चुना जाता है char

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

बाद में जावा और सी # जैसी भाषाओं ने कच्चे प्रदर्शन पर अपरिभाषित व्यवहार को समाप्त कर दिया।


-5

एक मायने में, जावा के पास भी है। मान लीजिए, आपने Arrays.sort को गलत तुलनित्र दिया। इसके अपवाद का पता लगा सकता है। अन्यथा यह किसी तरह से एक सरणी को छांटेगा जो किसी विशेष के लिए गारंटी नहीं है।

इसी प्रकार यदि आप कई थ्रेड्स से परिवर्तनशील हैं, तो परिणाम अप्रत्याशित भी होते हैं।

C ++ को अभी और अधिक स्थितियों को अपरिभाषित बनाने के लिए आगे बढ़ाया गया है (या जावा ने अधिक संचालन को परिभाषित करने का फैसला किया है) और इसके लिए एक नाम है।


4
हम यहां जिस तरह की बात कर रहे हैं, वह अपरिभाषित व्यवहार नहीं है। "गलत तुलनित्र" दो प्रकारों में आते हैं: वे जो कुल आदेश को परिभाषित करते हैं, और जो नहीं करते हैं। यदि आप एक तुलनित्र प्रदान करते हैं जो लगातार वस्तुओं के सापेक्ष क्रम को परिभाषित करता है, तो व्यवहार अच्छी तरह से परिभाषित है, यह सिर्फ व्यवहार नहीं है जो प्रोग्रामर चाहता था। यदि आप एक तुलनित्र प्रदान करते हैं जो सापेक्ष क्रम के बारे में सुसंगत नहीं है, तो व्यवहार अभी भी अच्छी तरह से परिभाषित है: सॉर्ट फ़ंक्शन एक अपवाद को फेंक देगा (जो शायद प्रोग्रामर नहीं चाहता था वह व्यवहार भी है)।
मार्क

2
चरों को संशोधित करने के लिए, दौड़ की स्थिति को आमतौर पर अपरिभाषित व्यवहार नहीं माना जाता है। मुझे यह जानकारी नहीं है कि जावा साझा डेटा को असाइनमेंट कैसे संभालता है, लेकिन भाषा के सामान्य दर्शन को जानते हुए, मुझे पूरा यकीन है कि यह परमाणु होना आवश्यक है। इसके साथ ही 53 और 71 को असाइन aकरना अपरिभाषित व्यवहार होगा यदि आप इसमें से 51 या 73 प्राप्त कर सकते हैं, लेकिन यदि आप केवल 53 या 71 प्राप्त कर सकते हैं, तो यह अच्छी तरह से परिभाषित है।
मार्क

@Mark सिस्टम के मूल शब्द आकार से बड़े डेटा के साथ (उदाहरण के लिए, 16-बिट शब्द आकार सिस्टम पर 32 बिट चर), यह संभव है कि प्रत्येक 16-बिट भाग को अलग से संग्रहीत करने के लिए एक आर्किटेक्चर की आवश्यकता हो। (SIMD एक और संभावित ऐसी स्थिति है।) उस मामले में, यहां तक ​​कि एक साधारण स्रोत-कोड-स्तरीय असाइनमेंट भी जरूरी नहीं है जब तक कि संकलक द्वारा यह सुनिश्चित करने के लिए विशेष देखभाल नहीं की जाती है कि इसे परमाणु रूप से निष्पादित किया गया है।
एक सीवीएन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.