4

update: I've now re-tested both a simplified test case and the full code with the shared names reinstated, and it works correctly. There probably was some other error somewhere else in my code which is now fixed. Sorry for wasting your time and effort; will never post without a working test case in the future. Mea culpa.


I have a C++ function which I call repeatedly. It has the following snippet in it

     switch(c)
     {
     case 1:
        {
          static int i = 0;
          if ( ... )  { i = 0; }
          .... 
          break;
        }
     case 2:
        {
          static int i = 0;
          if ( ... )  { i = 0; }
          .... 
          break;
        }
     case 3:
        {
          static int i = 0;
          if ( ... )  { i = 0; }
          .... 
          break;
        }
     }

The idea is that it must remember its state per each case, and sometimes it must reset it.

It didn't work properly. When I was debugging it (MSVC++ 2010 Express Edition) I noticed that each i was not behaving independently and their values were changing seemingly by themselves; moreover when the re-set condition was hit, the corresponding if was entered OK but the i = 0; statement was just ... skipped over!!! And the "locals" window showed i with its previous value, unchanged (while the current statement was the next one, still inside the if). Other statements inside the if were executing properly.

When I renamed each i with a unique name (i1, i2, i3), the problem went away.

Is this some bug, or some language feature that I should know? I thought each block { ... } defines independent scope. What is going on here? Would it work in C?

edit: sorry for not constructing the test case. Will do so, and report back later.

darveter
  • 81
  • 7
  • 1
    Could you provide a test case demonstrating exactly what you're seeing? (i.e. a small program, the expected output, and the (unexpected) actual output.) If it really is treating all those variables as the same, then that's a bug; but it's impossible to tell from the example code what your real code might look like. – Mike Seymour Feb 26 '14 at 12:47
  • I can't, not in a timely manner, sorry. But any simple thing will do. Say, when (each) `i` hits 4, reset it to 0; and when it's `==c`, print it out. then call the function with `c` = 1,2,1,3,1,2,1,3,1,2,1,3,1,2,1... and the error should show up. – darveter Feb 26 '14 at 12:51
  • 3
    Unfortunately, if you can't provide code to demonstrate the problem, we can't guess what the problem might be. They should all be independent variables; if they behave as if they're not, then there's a bug in either the compiler, your code, or your interpretation of its behaviour. I suspect it's not the compiler. – Mike Seymour Feb 26 '14 at 12:54
  • @ДарВетер My answer shows a "simple thing" that certainly doesn't reproduce the problem you're describing. You should construct testcases during your own debugging, long before posting here! And when you _do_ eventually post here, you should post the testcase. (Also, which version of MSVC++? There have been _many_.) Thanks! – Lightness Races in Orbit Feb 26 '14 at 12:55
  • @MikeSeymour I will, it'll just take me some time. – darveter Feb 26 '14 at 12:57
  • @LightnessRacesinOrbit thanks for your comments. Will follow. And it's Visual C++ 2010 Express edition. – darveter Feb 26 '14 at 12:58
  • @MikeSeymour my bad; sorry for the wasted time and effort; there was some other error in my code probably. Many thanks. – darveter Feb 26 '14 at 13:50

4 Answers4

6

This sounds like a bug in your code or interpretation. I can well imagine a "watch window" feature in your debugger getting this wrong, since blocks don't have names and will therefore be difficult to identify in text.

Local variables with static storage duration are bound by block scope.

Here's proof that they do not have function scope:

[C++11: 3.3.5/1]: Labels (6.1) have function scope and may be used anywhere in the function in which they are declared. Only labels have function scope.

And here's a practical demonstration:

#include <iostream>

void f(const int i)
{
    switch (i) {
        case 3: {
            static int x = 0;
            std::cout << x;
            x = 3;
            std::cout << x << ' ';
            break;
        }

        case 4: {
            static int x = 0;
            std::cout << x;
            x = 4;
            std::cout << x << ' ';
            break;
        }
    }
}

int main()
{
    f(3);
    f(4);
}

// Output: 03 04

This shows that when the second case is entered, you are working with a different local, static variable x. Otherwise you would see 03 34.

Live demo using GCC 4.8; I get the same result with Visual Studio 2012.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
4

Static variables inside the function have a block scope and they are persistent over consecutive calls to it. You cannot declare two variables with same name in same scope but you can do it if they are in different scopes denoted as

{}

which is in your case.

switch(c)
 {
 case 1:
    {
      static int i = 0;
    }
 case 2:
    {
      static int i = 0;
    }
 case 3:
    {
      static int i = 0; 
    }
 }

So this should work as you expected and thus probably this is the bug in compiler, debugger (or somewhere else what is hard to guess without more information given) which treats all these static variables as the same variable. This is why changing names of these variables fixes your problem.

4pie0
  • 29,204
  • 9
  • 82
  • 118
1

I had to check for myself, thought I'll share my little test. the variables are only visible inside the case curly brackets. and the same variable name can be declared inside another case and it won't overwrite the other variable.

the variables are not visible in the function though, only inside the curly braces in the switch statement.

#include<stdio.h>
int call_switch(int);
int main()
{
call_switch(2);
call_switch(3);
call_switch(2);
call_switch(3);
return 0;
}

int call_switch(int a){
switch(a)
{ 
   case 2:
   {
     static int i = 5;
     i++;
     printf(" i declared as 5     %d\n",i);
     break;
   }
   case 3:
   {
     static int i = 10;
     i++;
     printf("i declared as 10   %d\n",i);
     break;
   }
}
  // printf("%d",i ); not visible here
  return 0;

}

output was

i declared as  5     6
i declared as 10    11
i declared as  5     7
i declared as 10    12
tesseract
  • 891
  • 1
  • 7
  • 16
-1

static variables inside a function have function scope. The variable is visible in the whole of the function.

static variables outside the function have file scope, which is visible inside the file, but not across files.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Sakthi Kumar
  • 3,047
  • 15
  • 28
  • wouldn't the compiler then give an error about multiple declarations of the same variable? Could you give me a link to some docs about this? -- Isn't each block defining a separate scope? I thought it's impossible to refer to the variable defined inside a {...} block outside that block , even inside the same function. (?) – darveter Feb 26 '14 at 12:33
  • It sees the variable **declaration** is inside another `block {}` and that is why it does not generate any warning – Sakthi Kumar Feb 26 '14 at 12:37
  • I thought it's impossible to refer to the variable defined inside a {...} block outside that block , even inside the same function. (?) So they must be separate vars, no? – darveter Feb 26 '14 at 12:37
  • 5
    No, static variables have *block* scope; these should be separate variables, since they are in separate blocks. If the compiler really does fold them into a single variable, then that's a bug. (I suspect the problem is with interpreting the debugger's output though). – Mike Seymour Feb 26 '14 at 12:40
  • so I can't refer to it outside its { ... } block, but it *is* defined outside the { ... } block? – darveter Feb 26 '14 at 12:42
  • @MikeSeymour the program didn't run properly - was erroring out. With vars renamed, it ran OK. When I debugged it, it was simple hitting F10 for step over. Enter the IF: OK, execute next (re-set) statement: NOT OK; execute next statmt: OK again. What's there to mis-interpret? :) – darveter Feb 26 '14 at 12:43
  • @Sakthi: `3.3.5/1` says: _Labels (6.1) have function scope and may be used anywhere in the function in which they are declared. Only labels have function scope_ – Lightness Races in Orbit Feb 26 '14 at 12:44
  • @LightnessRacesinOrbit that makes sense, thank you! Any confirmation on that though?... Or if you are really *sure*, I can take your word on it. :) ... Wait, now you're saying, it's not so? – darveter Feb 26 '14 at 12:46
  • @ДарВетер: Mike is correct. – Lightness Races in Orbit Feb 26 '14 at 12:49
  • 1
    This answer is completely wrong and doesn't answer the question. _Function scope_ as defined by the standards, only relates to goto-labels. Even still, the statics in this question are in local blocks within each case. They have _block scope_. – Lundin Feb 26 '14 at 13:06