2013-06-19 24 views
14

कुछ 3 पार्टी सी कोड मैं की तरह कुछ में आए की समीक्षा:स्विच मामले अजीब scoping

switch (state) { 
case 0: 
    if (c=='A') { // open brace 
     // code... 
    break; // brace not closed! 
case 1: 
    // code... 
    break; 
    } // close brace! 
case 2: 
    // code... 
    break; 
} 

कौन सा कोड में मैं की समीक्षा दिखाई दिया था सिर्फ एक टाइपो होने के लिए, लेकिन मुझे लगता है कि इसे बाहर त्रुटि के साथ संकलित आश्चर्य हुआ।

यह मान्य सी क्यों है?
अपेक्षित जगह पर ब्रेस बंद करने की तुलना में इस कोड के निष्पादन पर असर क्या है?
क्या कोई ऐसा मामला है जहां इसका उपयोग किया जा सकता है?

संपादित करें: उदाहरण में मैं सब टूट जाता है को देखा उपस्थित थे (जैसा कि ऊपर) - लेकिन इस सवाल का जवाब भी व्यवहार शामिल हो सकते हैं, तो तोड़ने के मामले 0 या 1.

+0

ठीक है, यह 'स्विच-केस' के अजीब 'गोटो लेबल 'कार्यान्वयन के कारण है। जबकि आपका विशेष मामला शायद थोड़ा अजीब और उपयोग के मामले में आने के लिए मुश्किल है (हालांकि [* डफ की डिवाइस *] (http://en.wikipedia.org/wiki/Duff%27s_device) देखें, हालांकि, गिरावट के मामलों की सामान्य अवधारणा (जब आप 'ब्रेक' छोड़ देते हैं) वास्तव में काफी उपयोगी हो सकते हैं। –

+2

यदि आप अब * डफ के डिवाइस * कैसे काम करते हैं, इस बारे में स्पष्टीकरण चाहते हैं, [यहां] (http://stackoverflow.com/questions/514118/how-does-duffs-device-work) कुछ हैं। – devnull

+0

इस मामले में 'केस 1:' का संकलन एक अलग लेबल के रूप में किया जा रहा है। वाक्यविन्यास पूरी तरह से मान्य है, लेकिन लगभग निश्चित रूप से (संदर्भ से) इस स्थिति में एक तर्क त्रुटि है। इसे 'state == 1' भेजकर परीक्षण करें और आपको गलत परिणाम दिखाई देगा। – Chad

उत्तर

12

में अनुपस्थित यह मान्य, समान संरचना इतना ही नहीं किया गया है है वास्तविक कोड, जैसे, Duff's Device है, जो एक बफर कॉपी करने के लिए एक unrolled पाश है में इस्तेमाल किया:

send(to, from, count) 
register short *to, *from; 
register count; 
{ 
     register n = (count + 7)/8; 
     switch(count % 8) { 
     case 0: do { *to = *from++; 
     case 7:   *to = *from++; 
     case 6:   *to = *from++; 
     case 5:   *to = *from++; 
     case 4:   *to = *from++; 
     case 3:   *to = *from++; 
     case 2:   *to = *from++; 
     case 1:   *to = *from++; 
       } while(--n > 0); 
     } 
} 

के बाद से एक switch बयान वास्तव में सिर्फ एक पते की गणना करता है और इसे करने के लिए कूदता है, यह देखने के लिए क्यों यह दूसरे के साथ ओवरलैप कर सकते हैं आसान है नियंत्रण संरचनाएं; अन्य नियंत्रण संरचनाओं के भीतर की रेखाओं में ऐसे पते हैं जो कूद लक्ष्य भी हो सकते हैं!

आपके द्वारा प्रस्तुत किए गए मामले में, कल्पना करें कि क्या आपके कोड में switch या break एस नहीं है। जब आप if कथन के then भाग को निष्पादित करना समाप्त कर लेते हैं, तो आप बस चलते रहेंगे, इसलिए आप case 2: में आ जाएंगे। अब, चूंकि आपके पास switch और break है, यह महत्वपूर्ण है कि break क्या टूट सकता है। MSDN page, “The C break statement” के अनुसार,

तोड़ बयान enclosing निकटतम के लिए, कर के निष्पादन, स्विच, या जबकि बयान है जिसमें ऐसा लगता है समाप्त हो जाता है। नियंत्रण उस कथन को पास करता है जो समाप्त कथन का पालन करता है।

के बाद से निकटतम करते हैं, के लिए enclosing, स्विच, या जबकि बयान अपने स्विच (सूचना है कि अगर उस सूची में शामिल नहीं है), तो अगर आप 'है then ब्लॉक के अंदर फिर से, आप switch कथन के बाहर स्थानांतरित कर सकते हैं। थोड़ा और दिलचस्प क्या है, हालांकि, अगर आप case 0 दर्ज करते हैं तो क्या होता है, लेकिन c == 'A' गलत है। फिर ifthen ब्लॉक की समाप्ति ब्रेस के ठीक बाद नियंत्रण स्थानांतरित करता है, और आप case 2 में कोड निष्पादित करना प्रारंभ करते हैं।

+1

सी! = 'ए' केस समझ में आता है जिस तरह से आप इसे समझाते हैं - लेकिन यह कोड पर त्वरित नज़र से अंतर्ज्ञानी से FAR है! – Ricibob

+0

@Ricibob यह स्वीकार करता है कि सी को "उच्च स्तरीय असेंबली" के रूप में देखने की एक निश्चित राशि है, मैं मानता हूं। यदि आपने कुछ समय बिताया है कि सी कोड को असेंबली/मशीन कोड में कैसे संकलित किया गया है, तो यह थोड़ा आसान हो जाता है। उदाहरण के लिए, 'अगर शर्त' तो कथन में, केवल एक ही कूद है; अगर स्थिति _false_ है, तो 'फिर' भाग के ठीक बाद कूदें। यदि आप 'फिर' भाग में समाप्त होते हैं, तो निरंतर निष्पादन आपको वहां भी ले जाएगा। 'ब्रेक' की कोई ज़रूरत नहीं है। एक पुनरावृत्ति रूप में, उदाहरण के लिए, '' हालत ब्लॉक 'के दौरान, ब्लॉक को परीक्षण करने के लिए शुरुआत में वापस कूदने के लिए संकलित किया जाता है ... –

+0

@Ricibob ... फिर से स्थिति, और फिर ब्लॉक में फिर से जाएं, या बाद में कूदें खंड। तो पुनरावृत्ति संरचनाओं को 'ब्रेक' की आवश्यकता होती है क्योंकि शरीर उन्हें शुरुआत में वापस लाएगा। हालांकि 'स्विच' एक अजीब तरह का है, क्योंकि यह पुनरावृत्ति नहीं करता है। इसे सिर्फ 'ब्रेक' की आवश्यकता है क्योंकि यह बहुत आम है कि प्रोग्रामर केवल एक मामले को निष्पादित करना चाहते हैं और बाकी के माध्यम से नहीं गिरना चाहते हैं, और बिना ब्रेक के उन्हें स्विच स्टेटमेंट के बाद एक नया लेबल लिखना होगा और प्रत्येक मामले से इसे 'गोटो' करना होगा । किसी भी मामले में, संभवतः इस तरह के नियंत्रण प्रवाह इंटरलीविंग करने के लिए यह अच्छी शैली नहीं है जब तक कि आपके पास ... –

3

सी और सी ++ में लूप में कूदना कानूनी है और यदि आप किसी भी परिवर्तनीय घोषणाओं पर कूद नहीं करते हैं तो ब्लॉक इतने लंबे होते हैं। goto का उपयोग करके उदाहरण के लिए आप this answer देख सकते हैं, लेकिन मुझे नहीं लगता कि क्यों एक ही विचार switch ब्लॉक पर लागू नहीं होंगे।

}case 1 से ऊपर था, तो सेमेन्टिक्स अलग हैं, जैसा कि आप उम्मीद करेंगे।
यह कोड वास्तव में कहता है कि state == 0 और c != 'A' फिर case 2 पर जाएं, जहां से if कथन का समापन ब्रेस है। फिर यह उस कोड को संसाधित करता है और case 2 कोड के अंत में break कथन को हिट करता है।

+0

+1 वेरिएबल घोषणाओं को छोड़ने के बारे में उल्लेख करने के लिए +1 – legends2k

संबंधित मुद्दे