c++ - शकर - एक स्विच स्टेटमेंट में चर क्यों घोषित नहीं किया जा सकता है?



व्हाट इस स (16)

अधिकांश उत्तरों अब तक एक सम्मान में गलत हैं: आप केस स्टेटमेंट के बाद चर घोषित कर सकते हैं , लेकिन आप उन्हें प्रारंभ नहीं कर सकते हैं:

case 1:
    int x; // Works
    int y = 0; // Error, initialization is skipped by case
    break;
case 2:
    ...

जैसा कि पहले उल्लेख किया गया है, इसके आसपास एक अच्छा तरीका है अपने मामले के लिए एक दायरा बनाने के लिए ब्रेसिज़ का उपयोग करना।

https://src-bin.com

मैंने हमेशा यह सोचा है - स्विच स्टेटमेंट में केस लेबल के बाद आप चर क्यों घोषित नहीं कर सकते? सी ++ में आप चर कहीं भी चर घोषित कर सकते हैं (और उन्हें पहले उपयोग के करीब घोषित करना स्पष्ट रूप से एक अच्छी बात है) लेकिन निम्नलिखित अभी भी काम नहीं करेंगे:

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}  

उपरोक्त मुझे निम्नलिखित त्रुटि देता है (एमएससी):

'न्यूवेल' की शुरुआत 'केस' लेबल से छोड़ी गई है

यह अन्य भाषाओं में भी एक सीमा प्रतीत होता है। यह ऐसी समस्या क्यों है?


Answer #1

अब तक उत्तर सी ++ के लिए रहे हैं।

सी ++ के लिए, आप प्रारंभिकरण पर कूद नहीं सकते हैं। आप सी में कर सकते हैं। हालांकि, सी में, एक घोषणा एक बयान नहीं है, और मामले के लेबलों को बयान के बाद पालन करना होगा।

तो, मान्य (लेकिन बदसूरत) सी, अमान्य सी ++

switch (something)
{
  case 1:; // Ugly hack empty statement
    int i = 6;
    do_stuff_with_i(i);
    break;
  case 2:
    do_something();
    break;
  default:
    get_a_life();
}

इसके विपरीत, सी ++ में, एक घोषणा एक बयान है, इसलिए निम्नलिखित मान्य सी ++, अमान्य सी है

switch (something)
{
  case 1:
    do_something();
    break;
  case 2:
    int i = 12;
    do_something_else();
}

Answer #2

इस प्रश्न को एक ही समय में [सी] और [सी ++] के रूप में टैग किया गया है। मूल कोड वास्तव में सी और सी ++ दोनों में अमान्य है, लेकिन पूरी तरह से अलग असंबंधित कारणों से। मेरा मानना ​​है कि मौजूदा उत्तरों से इस महत्वपूर्ण विवरण को याद किया गया था (या obfuscated)।

  • सी ++ में यह कोड अमान्य है क्योंकि case ANOTHER_VAL: लेबल वैरिएबल newVal के दायरे में अपने प्रारंभिक newVal के दायरे में कूदता है। कूदता है कि स्थानीय वस्तुओं के प्रारंभिक बाईपास सी ++ में अवैध हैं। इस मुद्दे के इस पक्ष को ज्यादातर उत्तरों द्वारा सही ढंग से संबोधित किया जाता है।

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

    switch (val)  
    {  
    case VAL:             /* <- C error is here */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:     /* <- C++ error is here */
      ...
      break;
    }
    

एक अतिरिक्त {} ब्लॉक जोड़ना सी ++ और सी दोनों समस्याओं को हल करता है, भले ही ये समस्याएं बहुत अलग हों। सी ++ पक्ष पर यह newVal के दायरे को प्रतिबंधित करता है, यह सुनिश्चित कर रहा है कि case ANOTHER_VAL: अब उस दायरे में कूदता है, जो C ++ समस्या को समाप्त करता है। सी पक्ष पर अतिरिक्त {} एक यौगिक बयान प्रस्तुत करता है, इस प्रकार case VAL: बना देता case VAL: एक कथन पर लागू करने के लिए लेबल, जो सी मुद्दे को समाप्त करता है।

  • सी मामले में समस्या आसानी से {} बिना सुलझाया जा सकता है। case VAL: बाद बस एक खाली कथन जोड़ें case VAL: लेबल और कोड मान्य हो जाएगा

    switch (val)  
    {  
    case VAL:;            /* Now it works in C! */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:  
      ...
      break;
    }
    

    ध्यान दें कि भले ही यह सी बिंदु के दृष्टिकोण से मान्य है, फिर भी यह C ++ बिंदु दृश्य से अमान्य है।

  • समरूप रूप से, सी ++ मामले में समस्या को {} बिना आसानी से हल किया जा सकता है। बस परिवर्तनीय घोषणा से प्रारंभकर्ता को हटा दें और कोड मान्य हो जाएगा

    switch (val)  
    {  
    case VAL: 
      int newVal;
      newVal = 42;  
      break;
    case ANOTHER_VAL:     /* Now it works in C++! */
      ...
      break;
    }
    

    ध्यान दें कि भले ही यह अब C ++ दृष्टिकोण से मान्य है, यह सी बिंदु के दृष्टिकोण से अमान्य है।


Answer #3

इसे इस्तेमाल करे:

switch (val)
{
    case VAL:
    {
        int newVal = 42;
    }
    break;
}

Answer #4

ऐसा प्रतीत होता है कि अज्ञात वस्तुओं को स्विच केस स्टेटमेंट में घोषित या बनाया जा सकता है, जिसके कारण उन्हें संदर्भित नहीं किया जा सकता है और जैसे कि अगले मामले में नहीं आ सकता है। इस उदाहरण पर विचार करें जीसीसी 4.5.3 और विजुअल स्टूडियो 2008 पर संकलित (शायद एक अनुपालन मुद्दा हो सकता है 'इसलिए विशेषज्ञों का वजन कम हो)

#include <cstdlib>

struct Foo{};

int main()
{
    int i = 42;

    switch( i )
    {
    case 42:
        Foo();  // Apparently valid
        break;

    default:
        break;
    }
    return EXIT_SUCCESS;
}

Answer #5

ठीक। इसे स्पष्ट करने के लिए केवल सख्ती से घोषणा के साथ कुछ लेना देना नहीं है। यह केवल "प्रारंभिक पर कूदने" से संबंधित है (आईएसओ सी ++ '03 6.7 / 3)

यहां दी गई कई पोस्टों में उल्लेख किया गया है कि घोषणा पर कूदने से परिवर्तनीय "घोषित नहीं किया जा सकता"। यह सच नहीं है। एक पीओडी ऑब्जेक्ट को प्रारंभकर्ता के बिना घोषित किया जा सकता है लेकिन इसका अनिश्चित मूल्य होगा। उदाहरण के लिए:

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' initialized to 0, but this statement
            // is jumped when 'i == 1'
     break;
   case 1:
     ++j;   // 'j' is in scope here - but it has an indeterminate value
     break;
}

जहां ऑब्जेक्ट एक गैर-पीओडी या समेकित है, संकलक पूरी तरह से प्रारंभकर्ता जोड़ता है, और इसलिए इस तरह की घोषणा पर कूदना संभव नहीं है:

class A {
public:
  A ();
};

switch (i)  // Error - jumping over initialization of 'A'
{
   case 0:
     A j;   // Compiler implicitly calls default constructor
     break;
   case 1:
     break;
}

यह सीमा स्विच स्टेटमेंट तक ही सीमित नहीं है। शुरुआत में कूदने के लिए 'गोटो' का उपयोग करने में भी एक त्रुटि है:

goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;

थोड़ी सी बात यह है कि सी ++ और सी में सी के बीच यह अंतर है, शुरुआत में कूदने में कोई त्रुटि नहीं है।

जैसा कि अन्य ने उल्लेख किया है, समाधान एक नेस्टेड ब्लॉक जोड़ना है ताकि चर का जीवनकाल अलग-अलग केस लेबल तक सीमित हो।


Answer #6

नए चर केवल ब्लॉक स्कोप पर decalared किया जा सकता है। आपको ऐसा कुछ लिखना होगा:

case VAL:  
  // This will work
  {
  int newVal = 42;  
  }
  break;

बेशक, newVal केवल ब्रेसिज़ के भीतर गुंजाइश है ...

चीयर्स, राल्फ


Answer #7

नया वैल स्विच के पूरे दायरे में मौजूद है लेकिन केवल वैल्यू अंग हिट होने पर ही शुरू किया जाता है। यदि आप VAL में कोड के चारों ओर एक ब्लॉक बनाते हैं तो यह ठीक होना चाहिए।


Answer #8

मेरा मानना ​​है कि इस मुद्दे पर हाथ यह है कि कथन छोड़ दिया गया था, और आपने अन्य जगहों का उपयोग करने की कोशिश की, इसे घोषित नहीं किया जाएगा।


Answer #9

मेरी पसंदीदा बुराई स्विच चाल एक अवांछित केस लेबल पर जाने के लिए if (0) का उपयोग करना है।

switch(val)
{
case 0:
// Do something
if (0) {
case 1:
// Do something else
}
case 2:
// Do something in all cases
}

लेकिन बहुत बुराई।


Answer #10

मैंने इस सवाल के लिए मूल रूप से यह जवाब लिखा था। हालांकि जब मैंने इसे समाप्त किया तो मैंने पाया कि जवाब बंद कर दिया गया है। इसलिए मैंने इसे यहां पोस्ट किया है, शायद कोई भी जो मानक के संदर्भ पसंद करता है उसे उपयोगी लगेगा।

प्रश्न में मूल कोड:

int i;
i = 2;
switch(i)
{
    case 1: 
        int k;
        break;
    case 2:
        k = 1;
        cout<<k<<endl;
        break;
}

वास्तव में 2 प्रश्न हैं:

1. case लेबल के बाद मैं एक चर घोषित क्यों कर सकता हूं?

ऐसा इसलिए है क्योंकि सी ++ लेबल में फॉर्म होना चाहिए:

एन 3337 6.1 / 1

लेबल बयान:

...

  • विशेषता-विनिर्देशक-सेकोप्ट case constant-expression : statement

...

और C++ घोषणा कथन में कथन के रूप में भी माना जाता है ( C विपरीत):

एन 3337 6/1:

कथन :

...

घोषणापत्र का बयान

...

2. मैं परिवर्तनीय घोषणा पर कूद क्यों कर सकता हूं और फिर इसका उपयोग कर सकता हूं?

क्योंकि: N3337 6.7 / 3

एक ब्लॉक में स्थानांतरित करना संभव है, लेकिन इस तरह से नहीं कि प्रारंभिकरण के साथ घोषणाओं को छोड़ दिया जाए । एक कार्यक्रम जो कूदता है (एक स्विच स्टेटमेंट की स्थिति से हस्तांतरण को किसी मामले लेबल में हस्तांतरण माना जाता है ।)

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

चूंकि के स्केलर प्रकार का है , और इसकी घोषणा पर कूदने की घोषणा के बिंदु पर प्रारंभ नहीं किया गया है। यह अर्थात् समकक्ष है:

goto label;

int x;

label:
cout << x << endl;

हालांकि यह संभव नहीं होगा, अगर x घोषणा के बिंदु पर शुरू किया गया था:

 goto label;

    int x = 58; //error, jumping over declaration with initialization

    label:
    cout << x << endl;

Answer #11

यदि आपका कोड "int newVal = 42" कहता है तो आप उचित रूप से उम्मीद करेंगे कि नया वैल कभी अनियंत्रित नहीं होगा। लेकिन अगर आप इस कथन पर गए हैं (जो आप कर रहे हैं) तो यह वही होता है - नया वैल इन-स्कोप है लेकिन उसे असाइन नहीं किया गया है।

यदि आप वास्तव में ऐसा करना चाहते हैं तो भाषा को "int newVal; newVal = 42;" कहकर स्पष्ट करना होगा। अन्यथा आप एक ही मामले में newVal के दायरे को सीमित कर सकते हैं, जो आप चाहते थे कि अधिक संभावना है।

यदि आप एक ही उदाहरण पर विचार करते हैं तो यह चीजों को स्पष्ट कर सकता है लेकिन "const int newal = 42;"


Answer #12

सभी उत्तरों और कुछ और शोध पढ़ने के बाद मुझे कुछ चीजें मिलती हैं।

Case statements are only 'labels'

सी में, विनिर्देश के अनुसार,

§6.8.1 लेबल किए गए वक्तव्य:

labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement

सी में कोई खंड नहीं है जो "लेबल की घोषणा" की अनुमति देता है। यह सिर्फ भाषा का हिस्सा नहीं है।

इसलिए

case 1: int x=10;
        printf(" x is %d",x);
break;

यह संकलित नहीं होगा , http://codepad.org/YiyLQTYw देखें। जीसीसी एक त्रुटि दे रहा है:

label can only be a part of statement and declaration is not a statement

यहाँ तक की

  case 1: int x;
          x=10;
            printf(" x is %d",x);
    break;

यह संकलन भी नहीं कर रहा है , http://codepad.org/BXnRD3bu देखें। यहां मुझे भी वही त्रुटि मिल रही है।

विनिर्देश के अनुसार, सी ++ में,

लेबल-घोषणा की अनुमति है लेकिन लेबल किया गया है - आरंभिकरण की अनुमति नहीं है।

http://codepad.org/ZmQ0IyDG देखें।

ऐसी स्थिति के लिए समाधान दो है

  1. या तो {} का उपयोग करके नए दायरे का उपयोग करें

    case 1:
           {
               int x=10;
               printf(" x is %d", x);
           }
    break;
    
  2. या लेबल के साथ डमी कथन का उपयोग करें

    case 1: ;
               int x=10;
               printf(" x is %d",x);
    break;
    
  3. स्विच () से पहले वैरिएबल घोषित करें और केस स्टेटमेंट में इसे अलग-अलग मानों के साथ प्रारंभ करें यदि यह आपकी आवश्यकता को पूरा करता है

    main()
    {
        int x;   // Declare before
        switch(a)
        {
        case 1: x=10;
            break;
    
        case 2: x=20;
            break;
        }
    }
    

स्विच स्टेटमेंट के साथ कुछ और चीजें

स्विच में किसी भी कथन को कभी भी लिखें जो किसी भी लेबल का हिस्सा नहीं है, क्योंकि वे कभी निष्पादित नहीं होंगे:

switch(a)
{
    printf("This will never print"); // This will never executed

    case 1:
        printf(" 1");
        break;

    default:
        break;
}

http://codepad.org/PA1quYX3 देखें।


Answer #13

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

इस नियम को चित्रित करने के लिए कोड:

#include <iostream>

using namespace std;

class X {
  public:
    X() 
    {
     cout << "constructor" << endl;
    }
    ~X() 
    {
     cout << "destructor" << endl;
    }
};

template <class type>
void ill_formed()
{
  goto lx;
ly:
  type a;
lx:
  goto ly;
}

template <class type>
void ok()
{
ly:
  type a;
lx:
  goto ly;
}

void test_class()
{
  ok<X>();
  // compile error
  ill_formed<X>();
}

void test_scalar() 
{
  ok<int>();
  ill_formed<int>();
}

int main(int argc, const char *argv[]) 
{
  return 0;
}

प्रारंभकर्ता प्रभाव दिखाने के लिए कोड:

#include <iostream>

using namespace std;

int test1()
{
  int i = 0;
  // There jumps fo "case 1" and "case 2"
  switch(i) {
    case 1:
      // Compile error because of the initializer
      int r = 1; 
      break;
    case 2:
      break;
  };
}

void test2()
{
  int i = 2;
  switch(i) {
    case 1:
      int r;
      r= 1; 
      break;
    case 2:
      cout << "r: " << r << endl;
      break;
  };
}

int main(int argc, const char *argv[]) 
{
  test1();
  test2();
  return 0;
}

Answer #14

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

switch (val)
{   
case VAL:  
{
  // This will work
  int newVal = 42;  
  break;
}
case ANOTHER_VAL:  
...
break;
}

Answer #15

यदि आप एक नया ब्लॉक शुरू करते हैं तो आप एक स्विच स्टेटमेंट के भीतर चर घोषित कर सकते हैं:

switch (thing)
{ 
  case A:
  {
    int i = 0;  // Completely legal
  }
  break;
}

कारण स्थानीय चर के भंडारण के लिए ढेर पर आवंटन (और पुनः दावा) स्थान के साथ करना है।





switch-statement