काम करने के लिए माना जाता है कि क्या (0) एक स्विच में एक मामले को छोड़ने के लिए उपयोग कर रहा है?


122

मेरे पास एक ऐसी स्थिति है जहां मैं एक सी ++ स्विच स्टेटमेंट में दो मामलों के लिए चाहूंगा कि दोनों एक तीसरे मामले में आते हैं। विशेष रूप से, दूसरा मामला तीसरे मामले के माध्यम से गिर जाएगा, और पहला मामला दूसरे मामले से गुजरने के बिना तीसरे मामले में भी गिर जाएगा ।

मेरे पास एक गूंगा विचार था, यह कोशिश की, और यह काम किया! मैंने दूसरे मामले को एक if (0) {... में लपेटा }। यह इस तरह दिख रहा है:

#ifdef __cplusplus
#  include <cstdio>
#else
#  include <stdio.h>
#endif

int main(void) {
    for (int i = 0; i < 3; i++) {
        printf("%d: ", i);
        switch (i) {
        case 0:
            putchar('a');
            // @fallthrough@
            if (0) {        // fall past all of case 1 (!)
        case 1:
            putchar('b');
            // @fallthrough@
            }
        case 2:
            putchar('c');
            break;
        }
        putchar('\n');
    }
    return 0;
}

जब मैं इसे चलाता हूं, मुझे वांछित आउटपुट मिलता है:

0: ac
1: bc
2: c

मैंने इसे C और C ++ (दोनों क्लैंग के साथ) में आज़माया, और इसने यही काम किया।

मेरे प्रश्न हैं: क्या यह वैध C / C ++ है? क्या यह करना चाहिए जो यह करता है?


34
हां, यह वैध है और डफ के उपकरण के कारण ही उन्हीं कारणों से काम करता है।
dxiv

42
ध्यान दें कि इस तरह का कोड आपको ऐसे वातावरण में किसी भी कोड वॉकथ्रू से बाहर फेंक दिया जाएगा जो पठनीयता और स्थिरता के बारे में बहुत कम परवाह करता है।
एंड्रयू हेनले

16
यह भयानक है। डफ के उपकरण से भी ज्यादा भयानक, आपको बुरा लगता है। संबंधित, मैंने भी हाल ही में कुछ ऐसा देखा switch(x) { case A: case B: do_this(); if(x == B) also_do_that(); ... }। वह भी, IMO, भयानक था। कृपया, बस इस तरह से सामान लिखें जैसे कि कथन, भले ही इसका मतलब है कि आपको दो स्थानों में एक पंक्ति को दोहराना होगा। केवल एक ही स्थान पर गलती से बाद में अपडेट होने के जोखिम को कम करने के लिए फ़ंक्शन और चर (और प्रलेखन!) का उपयोग करें।
ilkkachu

50
:-) जो लोग उस कोड को देखने के कारण घायल हो गए थे या उन्हें चोट लगी थी, मैंने नहीं कहा कि यह एक अच्छा विचार था। वास्तव में, मैंने कहा कि यह एक गूंगा विचार था।
मार्क एडलर

4
ध्यान दें कि इस तरह से स्विच के अंदर निर्माण RAII के साथ अच्छी तरह से नहीं खेलते हैं :(
मूंग बतख

जवाबों:


58

हां, यह अनुमति है, और यह वही करता है जो आप चाहते हैं। एक switchकथन के लिए, C ++ मानक कहता है :

अपने आप में मामला और डिफ़ॉल्ट लेबल नियंत्रण के प्रवाह को परिवर्तित नहीं करते हैं, जो इस तरह के लेबल के बिना भी जारी रहता है। एक स्विच से बाहर निकलने के लिए, ब्रेक देखें।

[नोट १: आमतौर पर, सबस्टेशन जो एक स्विच का विषय होता है, कंपाउंड होता है और (कंपाउंड) सबस्टेशन के भीतर मौजूद टॉप-लेवल स्टेटमेंट पर डिफॉल्ट लेबल दिखाई देते हैं, लेकिन इसकी आवश्यकता नहीं है। घोषणाएँ एक स्विच स्टेटमेंट के विकल्प में दिखाई दे सकती हैं। - अंतिम नोट]

इसलिए जब ifबयान का मूल्यांकन किया जाता है, तो नियंत्रण के नियम एक ifबयान के नियमों के अनुसार बढ़ते हैं, चाहे मामले के लेबल की परवाह किए बिना।


13
इसके एक विशिष्ट मामले के रूप में, कोई पेट-मंथन मैक्रो के एक सेट के लिए Boost.Coroutines को देख सकता है जो इस नियम का लाभ उठाते हैं (और C ++ के अन्य आधा दर्जन कोने मामले) C ++ नियमों का उपयोग करके कोरटाइन लागू करते हैं। सी ++ 20 तक उन्हें भाषा का हिस्सा नहीं बनाया गया था, लेकिन इन मैक्रोज़ ने उन्हें काम कर दिया ... जब तक आप पहले अपने एंटासिड ले गए थे!
कोर्ट अमोन

60

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

उस के साथ, व्यवहार में, यह एक गोटो बयान के साथ लिखने के लिए शायद स्पष्ट है, जैसे:

    switch (i) {
    case 0:
        putchar('a');
        goto case2;
    case 1:
        putchar('b');
        // @fallthrough@
    case2:
    case 2:
        putchar('c');
        break;
    }

1
"जब एक ब्लॉक के बीच में कूदते हैं, तो गोटो के साथ एक ही कैविटीज़ चर के आरंभ पर कूदने के बारे में लागू होती है, आदि" वे कौन से कैविएट होंगे? आप चर के प्रारंभ पर कूद नहीं सकते
विंग्स

4
@AsteroidsWithWings, क्या आपका मतलब है कि मानकों के अनुरूप परिप्रेक्ष्य से, या एक कंपाइलर इसे अनुमति नहीं देगा? क्योंकि मेरा जीसीसी चेतावनी के साथ सी मोड में इसकी अनुमति देता है। हालांकि यह इसे C ++ मोड में अनुमति नहीं देता है।
ilkkachu

5
@quetzalcoatl gcc-9 और clang-6 दोनों इस कोड को अनुमति देते हैं, संभावित अनइंस्टॉलिज्ड के बारे में चेतावनी देते हैं bee(C मोड में; C ++ में वे इस केस लेबल / जंप बायपास वेरिएबल इनिशियलाइज़ेशन पर स्विच स्टेटमेंट से नहीं कूद सकते हैं)।
रुस्लान

7
आप जानते हैं gotoकि क्लीनर का उपयोग करते समय आप कुछ गलत कर रहे हैं।
कोनराड रुडोल्फ

9
@KonradRudolph: gotoबहुत अधिक दुर्भावनापूर्ण है, लेकिन इसके बारे में आपत्तिजनक कुछ भी नहीं है, यदि आप जटिल नियंत्रण संरचनाओं को मैन्युअल रूप से नहीं बना रहे हैं। संपूर्ण "गोटो को हानिकारक माना जाता है" एचएलएल (जैसे सी) कोड लिखने के बारे में था जो एक कंपाइलर द्वारा उत्सर्जित एएसएम की तरह दिखता है (पूरे स्थान पर आगे और पीछे jps)। गोटो के बहुत सारे संरचित उपयोग हैं जैसे फॉरवर्ड-ओनली (वैचारिक रूप से अलग breakया पहले से अलग नहीं return), असंभावित-रिट्री-लूप-ओनली (सामान्य प्रवाह पथ को अस्पष्ट करने से बचता है और नेस्टेड की कमी की भरपाई करता है continue), आदि
आर। GitHub STOP की मदद से ICE

28

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

यही कारण है कि switch ... caseबयान आमतौर पर फ़ंक्शन कॉल के साथ लिखे जाने चाहिए और बहुत सारे इनलाइन कोड नहीं होने चाहिए।

switch(i) {
case 0:
    do_zero_case(); do_general_stuff(); break;
case 1:
    do_one_case(); do_general_stuff(); break;
case 2:
    do_general_stuff(); break;
default:
    do_default_not_zero_not_one_not_general_stuff(); break;
}

ध्यान दें कि प्रश्न में कोड केवलdo_general_stuff डिफ़ॉल्ट के लिए नहीं है, केवल केस 2 (और 0 और 1) के लिए। हालांकि यह i0..2 रेंज के बाहर के लिए स्विच नहीं चलाता है ।
पीटर कॉर्ड्स

@PeterCordes - ध्यान दें कि उत्तर में कोड do_general_stuffडिफ़ॉल्ट के लिए नहीं है, केवल केस 2 (और 0 और 1) के लिए है।
पीट बेकर

एक सुझाव - शायद डिफ़ॉल्ट मामले को हटा दिया जाए या उसका नाम बदल दिया जाए? विभिन्न फ़ंक्शन नामों को याद करना काफी आसान है।
23.A20 पर I.Am.A.Guy

@PeteBecker: ओह, IDK मैं कैसे चूक गया generalऔर defaultअलग-अलग शब्द थे। OTOH, यह एक ज्ञात तथ्य है कि मनुष्य आम तौर पर अभी भी एक शब्द पढ़ सकते हैं यदि मध्य अक्षरों को तराशा जाता है; हम शुरुआत और अंत को देखते हैं, इसलिए केवल मध्य का अलग होना शायद स्किम्यबिलिटी के लिए आदर्श नहीं है। शायद do_उपसर्ग को हटा दें ।
पीटर कॉर्ड्स

1
@ सुपरकैट: वह "प्रसिद्ध तथ्य" अलग-अलग लोगों द्वारा बीच के अक्षरों को बदलने के बारे में नहीं है, बल्कि बस तब के क्रम को मिलाने के बारे में है। "अगर कब्र में सियालम सच है, तो आप चूल्हों को रखने के लिए आदी हो सकते हैं।"
माइकल करचर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.