1) गोटो का सबसे आम उपयोग जो मुझे पता है कि उन भाषाओं में अपवाद से निपटने का अनुकरण है जो इसे प्रस्तुत नहीं करते हैं, अर्थात् सी। (ऊपर परमाणु द्वारा दिए गए कोड बस यही है।) लिनक्स स्रोत कोड को देखें और आप ' एक bazillion गोटो को इस तरह से इस्तेमाल करते देखेंगे; 2013 में किए गए एक त्वरित सर्वेक्षण के अनुसार लिनक्स कोड में लगभग 100,000 गोटो थे: http://blog.regehr.org/archives/894 । लिनक्स कोडिंग स्टाइल गाइड में भी गोटो के उपयोग का उल्लेख किया गया है: https://www.kernel.org/doc/Documentation/CodingStyle । जैसे ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग को फंक्शन पॉइंटर्स के साथ पॉपुलेटेड स्ट्रक्चर्स का उपयोग करके इम्यूलेट किया जाता है, वैसे ही C प्रोग्रामिंग में गोटो का स्थान है। तो कौन सही है: डजस्क्रा या लिनुस (और सभी लिनक्स कर्नेल कोडर्स)? यह मूल रूप से सिद्धांत बनाम अभ्यास है।
हालांकि, सामान्य निर्माण / पैटर्न के लिए संकलक-स्तर का समर्थन और जांच नहीं करने के लिए सामान्य रूप से गेटा है: उन्हें गलत उपयोग करना आसान है और संकलन-समय की जांच के बिना बग का परिचय देना है। विंडोज और विजुअल सी ++ लेकिन सी मोड में एसईएच / वीईएच के माध्यम से अपवाद हैंडलिंग की पेशकश इस कारण से: अपवाद ओओपी भाषाओं के बाहर भी उपयोगी हैं, अर्थात एक प्रक्रियात्मक भाषा में। लेकिन कंपाइलर हमेशा आपके बेकन को नहीं बचा सकता है, भले ही वह भाषा में अपवादों के लिए सिंटैक्टिक समर्थन प्रदान करता हो। बाद के मामले के उदाहरण पर विचार करें प्रसिद्ध Apple एसएसएल "गोटो फेल" बग, जिसने सिर्फ एक गोटो को विनाशकारी परिणामों के साथ दोहराया ( https://www.imperialviolet.org/2014/02/22/applebug.html ):
if (something())
goto fail;
goto fail; // copypasta bug
printf("Never reached\n");
fail:
// control jumps here
आप संकलक-अपवादित अपवादों का उपयोग करके ठीक वैसा ही बग रख सकते हैं, जैसे C ++ में:
struct Fail {};
try {
if (something())
throw Fail();
throw Fail(); // copypasta bug
printf("Never reached\n");
}
catch (Fail&) {
// control jumps here
}
लेकिन अगर कंपाइलर विश्लेषण करता है और अगम्य कोड के बारे में आपको चेतावनी देता है, तो बग के दोनों प्रकारों से बचा जा सकता है। उदाहरण के लिए / W4 चेतावनी स्तर पर Visual C ++ के साथ संकलन करने से दोनों मामलों में बग का पता चलता है। उदाहरण के लिए जावा एक बहुत अच्छे कारण के लिए अनुपलब्ध कोड को निषिद्ध करता है (जहां वह इसे पा सकता है!): यह औसत जो के कोड में एक बग होने की संभावना है। जब तक गोटो निर्माण लक्ष्य की अनुमति नहीं देता है कि कंपाइलर आसानी से पता नहीं लगा सकता है, जैसे गोटो को गणना किए गए पते (**) के लिए, यह कंपाइलर के लिए डिक्स्ट्रा का उपयोग करने की तुलना में गोटो के साथ एक फ़ंक्शन के अंदर पहुंच योग्य कोड खोजने के लिए कोई कठिन नहीं है। -प्राप्त कोड।
(**) फुटनोट: बेसिक के कुछ संस्करणों में गणना की गई संख्याओं के लिए गॉटोस संभव हैं, उदाहरण के लिए GOTO 10 * x जहां x एक चर है। भ्रामक रूप से, फोरट्रान में "कंप्यूटेड गोटो" एक निर्माण को संदर्भित करता है जो सी में एक स्विच स्टेटमेंट के बराबर होता है। मानक सी भाषा में गणना गोटो को अनुमति नहीं देता है, लेकिन केवल गोटो को सांख्यिकीय / वाक्यगत रूप से घोषित लेबल के लिए अनुमति देता है। GNU C में हालांकि एक लेबल (unary, उपसर्ग और& ऑपरेटर) का पता प्राप्त करने के लिए एक एक्सटेंशन है और एक गोटो को प्रकार शून्य के एक चर में अनुमति देता है। इस अस्पष्ट उप-विषय पर अधिक जानकारी के लिए https://gcc.gnu.org/oniltocs/gcc/Labels-as-Values.html देखें । इस पोस्ट के बाकी लोग उस अस्पष्ट GNU C फीचर से चिंतित नहीं हैं।
मानक सी (यानी गणना नहीं की गई) गोटो आमतौर पर यही कारण नहीं है कि संकलन समय पर अनुपलब्ध कोड नहीं मिल सकता है। सामान्य कारण निम्नलिखित की तरह तर्क कोड है। दिया हुआ
int computation1() {
return 1;
}
int computation2() {
return computation1();
}
यह कंपाइलर के लिए बस उतना ही कठिन है जितना कि निम्नलिखित 3 निर्माणों में से किसी में भी पहुंच योग्य नहीं है:
void tough1() {
if (computation1() != computation2())
printf("Unreachable\n");
}
void tough2() {
if (computation1() == computation2())
goto out;
printf("Unreachable\n");
out:;
}
struct Out{};
void tough3() {
try {
if (computation1() == computation2())
throw Out();
printf("Unreachable\n");
}
catch (Out&) {
}
}
(मेरी ब्रेस-संबंधी कोडिंग शैली को क्षमा करें, लेकिन मैंने उदाहरणों को यथासंभव कॉम्पैक्ट रखने की कोशिश की।)
विजुअल C ++ / W4 (यहां तक कि / Ox के साथ) इनमें से किसी में भी पहुंच योग्य कोड खोजने में विफल रहता है, और जैसा कि आप शायद जानते हैं कि अगम्य कोड को खोजने की समस्या सामान्य रूप से अनिर्दिष्ट है। (यदि आप मेरे बारे में विश्वास नहीं करते हैं: https://www.cl.cam.ac.uk/teaching/2006/OptComp/slides/lecture02.pdf )
संबंधित मुद्दे के रूप में, सी गोटो का उपयोग केवल फ़ंक्शन के शरीर के अंदर अपवादों का अनुकरण करने के लिए किया जा सकता है। मानक सी लाइब्रेरी गैर-स्थानीय निकास / अपवादों के अनुकरण के लिए सेटजम्प () और लॉन्गजम्प () फ़ंक्शंस की जोड़ी प्रदान करती है, लेकिन अन्य भाषाओं की तुलना में इनमें कुछ गंभीर कमियां हैं। विकिपीडिया लेख http://en.wikipedia.org/wiki/Setjmp.h इस उत्तरार्द्ध मुद्दे को काफी अच्छी तरह से समझाता है। यह फ़ंक्शन जोड़ी विंडोज ( http://msdn.microsoft.com/en-us/library/yz2ez4as.aspx ) पर भी काम करती है , लेकिन शायद ही कोई उन्हें वहां इस्तेमाल करता हो क्योंकि SEH / VEH बेहतर है। यूनिक्स पर भी, मुझे लगता है कि सेटजम्प और लॉन्गजम्प बहुत ही कम उपयोग किए जाते हैं।
2) मुझे लगता है कि सी में गोटो का दूसरा सबसे आम उपयोग मल्टी-लेवल ब्रेक या मल्टी-लेवल जारी है, जो एक काफी अनियंत्रित उपयोग मामला है। याद रखें कि जावा गेटो लेबल की अनुमति नहीं देता है, लेकिन लेबल तोड़ने या लेबल जारी रखने की अनुमति देता है। Http://www.oracle.com/technetwork/java/simple-142616.html के अनुसार , यह वास्तव में सी में गोटो का सबसे आम उपयोग का मामला है (90% वे कहते हैं), लेकिन मेरे व्यक्तिपरक अनुभव में, सिस्टम कोड जाता है अधिक बार हैंडलिंग के लिए गोटो का उपयोग करना। शायद वैज्ञानिक कोड में या जहां ओएस अपवाद हैंडलिंग (विंडोज) प्रदान करता है तो बहु-स्तरीय निकास प्रमुख उपयोग के मामले हैं। वे वास्तव में अपने सर्वेक्षण के संदर्भ में कोई विवरण नहीं देते हैं।
जोड़ने के लिए संपादित: यह पता चलता है कि ये दो उपयोग पैटर्न कर्निघन और रिची की सी बुक में पाए जाते हैं, पृष्ठ 60 के आसपास (संस्करण पर निर्भर करता है)। नोट की एक और बात यह है कि दोनों उपयोग के मामलों में केवल आगे के गोटो शामिल हैं। और यह पता चला कि MISRA C 2012 संस्करण (2004 संस्करण के विपरीत) अब गोटो को अनुमति देता है, जब तक कि वे केवल आगे वाले होते हैं।