Why can't variables be declared in a switch statement?

后端 未结 23 3029
一生所求
一生所求 2020-11-21 05:15

I\'ve always wondered this - why can\'t you declare variables after a case label in a switch statement? In C++ you can declare variables pretty much anywhere (and declaring

相关标签:
23条回答
  • 2020-11-21 06:08

    I wrote this answer orginally for this question. However when I finished it I found that answer has been closed. So I posted it here, maybe someone who likes references to standard will find it helpful.

    Original Code in question:

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

    There are actually 2 questions:

    1. Why can I declare a variable after case label?

    It's because in C++ label has to be in form:

    N3337 6.1/1

    labeled-statement:

    ...

    • attribute-specifier-seqopt case constant-expression : statement

    ...

    And in C++ declaration statement is also considered as statement (as opposed to C):

    N3337 6/1:

    statement:

    ...

    declaration-statement

    ...

    2. Why can I jump over variable declaration and then use it?

    Because: N3337 6.7/3

    It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps (The transfer from the condition of a switch statement to a case label is considered a jump in this respect.)

    from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5).

    Since k is of scalar type, and is not initialized at point of declaration jumping over it's declaration is possible. This is semantically equivalent:

    goto label;
    
    int x;
    
    label:
    cout << x << endl;
    

    However that wouldn't be possible, if x was initialized at point of declaration:

     goto label;
    
        int x = 58; //error, jumping over declaration with initialization
    
        label:
        cout << x << endl;
    
    0 讨论(0)
  • 2020-11-21 06:09

    It appears that anonymous objects can be declared or created in a switch case statement for the reason that they cannot be referenced and as such cannot fall through to the next case. Consider this example compiles on GCC 4.5.3 and Visual Studio 2008 (might be a compliance issue tho' so experts please weigh in)

    #include <cstdlib>
    
    struct Foo{};
    
    int main()
    {
        int i = 42;
    
        switch( i )
        {
        case 42:
            Foo();  // Apparently valid
            break;
    
        default:
            break;
        }
        return EXIT_SUCCESS;
    }
    
    0 讨论(0)
  • 2020-11-21 06:11

    Case statements are only labels. This means the compiler will interpret this as a jump directly to the label. In C++, the problem here is one of scope. Your curly brackets define the scope as everything inside the switch statement. This means that you are left with a scope where a jump will be performed further into the code skipping the initialization.

    The correct way to handle this is to define a scope specific to that case statement and define your variable within it:

    switch (val)
    {   
    case VAL:  
    {
      // This will work
      int newVal = 42;  
      break;
    }
    case ANOTHER_VAL:  
    ...
    break;
    }
    
    0 讨论(0)
  • 2020-11-21 06:12

    You can't do this, because case labels are actually just entry points into the containing block.

    This is most clearly illustrated by Duff's device. Here's some code from Wikipedia:

    strcpy(char *to, char *from, size_t count) {
        int 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);
        }
    }
    

    Notice how the case labels totally ignore the block boundaries. Yes, this is evil. But this is why your code example doesn't work. Jumping to a case label is the same as using goto, so you aren't allowed to jump over a local variable with a constructor.

    As several other posters have indicated, you need to put in a block of your own:

    switch (...) {
        case FOO: {
            MyObject x(...);
            ...
            break; 
        }
        ...
     }
    
    0 讨论(0)
  • 2020-11-21 06:12

    I just wanted to emphasize slim's point. A switch construct creates a whole, first-class-citizen scope. So it is posible to declare (and initialize) a variable in a switch statement before the first case label, without an additional bracket pair:

    switch (val) {  
      /* This *will* work, even in C89 */
      int newVal = 42;  
    case VAL:
      newVal = 1984; 
      break;
    case ANOTHER_VAL:  
      newVal = 2001;
      break;
    }
    
    0 讨论(0)
提交回复
热议问题