Navigation



4.3 — File scope and the static keyword

In previous lessons, you learned about local variables (which have block scope) and global variables (which have program scope). There is one other level of scoping that variables can have: file scope.

A variable with file scope can be accessed by any function or block within a single file. To declare a file scoped variable, simply declare a variable outside of a block (same as a global variable) but use the static keyword:

static int nValue; // file scoped variable
float fValue; // global variable

int main()
{
    double dValue; // local variable
}

File scoped variables act exactly like global variables, except their use is restricted to the file in which they are declared (which means you can not extern them to other files). File scoped variables are not seen very often in C++ because they have most of the downsides of global variables, just on a smaller scale.

The static keyword

The static keyword is probably the most confusing keyword in the C++ language. This is because it has different meanings depending on where it is used. When applied to a variable declared outside of a block, it changes the variable from a global variable to a file scoped variable. When applied to a variable declared inside a block, it has a different meaning entirely!

By default, local variables have automatic duration, which means they are destroyed when the block they are declared in goes out of scope. You can explicitly declare a variable as having automatic duration by using the auto keyword, though this is practically never done because local variables are automatic by default, and it would be redundant.

Using the static keyword on local variables changes them from automatic duration to fixed duration (also called static duration). A fixed duration variable is one that retains it’s value even after the scope in which it has been created has been exited! Fixed duration variables are only created (and initialized) once, and then they are persisted throughout the life of the program.

The easiest way to show the difference between automatic and fixed duration variables is by example.

Automatic duration (default):

#include <iostream>

void IncrementAndPrint()
{
    using namespace std;
    int nValue = 1; // automatic duration by default
    ++nValue;
    cout << nValue << endl;
} // nValue is destroyed here

int main()
{
    IncrementAndPrint();
    IncrementAndPrint();
    IncrementAndPrint();
}

Each time IncrementAndPrint is called, a variable named nValue is created and assigned the value of 1. IncrementAndPrint increments nValue to 2, and then prints the value of 2. When IncrementAndPrint is finished running, the variable goes out of scope and is destroyed. Consequently, this program outputs:

2
2
2

Now consider the fixed scope version of this program. The only difference between this and the above program is that we’ve changed the local variable nValue from automatic to fixed duration by using the static keyword.

Fixed duration (using static keyword):

#include <iostream>

void IncrementAndPrint()
{
    using namespace std;
    static int s_nValue = 1; // fixed duration
    ++s_nValue;
    cout << s_nValue << endl;
} // s_nValue is not destroyed here, but becomes inaccessible

int main()
{
    IncrementAndPrint();
    IncrementAndPrint();
    IncrementAndPrint();
}

In this program, because s_nValue has been declared as static, s_nValue is only created and initialized (to 1) once. When it goes out of scope, it is not destroyed. Each time the function IncrementAndPrint() is called, the value of s_nValue is whatever we left it at previously. Consequently, this program outputs:

2
3
4

Using hungarian notation, it is common to prefix fixed duration variables with “s_”. Some programmers use “s” (which we don’t like as much because that letter is better used for structs) or “c_” (which we don’t like as much because it’s not as mnemonic).

One of the most common uses for fixed duration local variables is for unique identifier generators. When dealing with a large number of similar objects within a program, it is often useful to assign each one a unique ID number so they can be identified. This is very easy to do with a fixed duration local variable:

int GenerateID()
{
    static int nNextID = 0;
    return nNextID++;
}

The first time this function is called, it returns 0. The second time, it returns 1. Each time it is called, it returns a number one higher than the previous time it was called. You can assign these numbers as unique IDs for your objects. Because nNextID is a local variable, it can not be “tampered with” by other functions.

4.4 — Type conversion and casting
Index
4.2 — Global variables

30 comments to 4.3 — File scope and the static keyword

  • [...] the lesson on file scope and the static keyword, you learned that static variables keep their values and are not destroyed even after they go out [...]

  • Steven H.

    [ Code moved to the forum ]

  • [...] Prev/Next Posts « 4.1 — Blocks (compound statements) and local variables | Home | 4.3 — File scope and the static keyword » Tuesday, June 19th, 2007 at 8:22 [...]

  • carmen

    well .. if they become inaccessible … what’s the point? We can’t use them anyway … can we?

    • You can’t use them when they’re inaccessible, but you can use them if and when they do become accessible again. For example, each time IncrementAndPrint() is called, s_nValue comes back into scope with it’s previous value. This allows you to have a variable that keeps track of it’s value between calls without exposing that variable to other functions (which is dangerous, because they might change it).

    • MrAlshahawy

      Consider Static variable as a combination between Global and Local Variables benefits:

      Static takes the benefit of keeping its value after you go out of the scope just like Global, At the same time you avoid the downside of Global variable which is that any other functions may change its value causing unpredictable values.

    • jon

      Also, since it is only declared once and not every time the function is called, it conserves memory. Right?

  • Nicolas

    static at the file scope is a good idea in C, but it’s very bad practice in C++ (I heard it’s even deprecated). There are way better encapsulation mechanisms in C++.

    This tutorial looks like a s/printf/cout/ approach at learning C++. It’s actually teaching C with C++ syntax.

    • I’m a bit perplexed at your comment. The discussion on file scoped variables on this tutorial is all of 6 sentences, the last of which explicitly discourages their use (in previous tutorials, I talk about the downsides of global variables). The rest of this tutorial discusses fixed duration variables, which have a lot of utility in C++.

      Most of these earlier tutorials cover topics that C++ inherits from C. In my opinion, it’s highly useful for developing programmers have a solid understanding of these concepts before trying to understand things like classes, inheritance, and templates.

  • Hertz

    Helped me a lot to understand the static keyword. The explanation is very clear and useful. Thanks.

  • Niaz

    Hey Alex thank your very much. I got my concpet cleared not only about STATIC variable but other complex things such as Variable Passing Machanisam.

    Thanks
    Niaz

  • Alfreda

    They really thought of everything when they made C/++ programming language didn’t they? O_O

  • [...] 2007 Prev/Next Posts « 4.3 — File scope and the static keyword | Home | 4.5 — Enumerated types » Tuesday, June 19th, 2007 at 6:34 [...]

  • mens sana in corpore sano

    Hi Alex, you have great tutorial! I have one question, when working with multiple file:

    static int nValue = 0;
    
    void Increment_1()
    {
      using namespace std;
      nValue++;
      cout << "Increment_1: " << nValue << endl;
    }
    
    void Increment_2()
    {
      using namespace std;
      nValue += 2;
      cout << "Increment_2: " << nValue << endl;
    }
    

    Is there any different for the usage when im declaring file scope variable without static like code below? As my understanding, within this way nValue will be compiled as file scope variable. Am I right?

    int nValue = 0;
    
    void Increment_1()
    {
      using namespace std;
      nValue++;
      cout << "Increment_1: " << nValue << endl;
    }
    
    void Increment_2()
    {
      using namespace std;
      nValue += 2;
      cout << "Increment_2: " << nValue << endl;
    }
    

    Thanks!

  • Freyr

    If I make a multi-file program e.g. main.cpp, source1.cpp, source1.h and then apart from declaring functions in source1.h, I also declare some variables. If source1.h is included in main.cpp and source1.cpp, in which scope are the variables found? Are they global?

  • konda reddy

    excellent tutorial for static variable concept.
    thanks Alex.

  • Brad

    I assume static variables reset every time the program is exited? Is there a way to keep a variables value even after the program ends? Say for instance you wanted to create a counter that keeps up with how many time a program was run or a particular function was called?

  • Alex, thank you for this excellent tutorial! Great explanation of what is otherwise quite a tricky set of concepts.

  • CodeChaos

    The name “file scope” is technically incorrect. It can even be misleading. For example, consider you have two files, eg.h and eg.cpp:

    eg.h

    static int myvar; //file scope!?

    eg.cpp

    #include "eg.h"
    
    int main()
    {
       myvar = 2; //this is OK. what!?
       return 0;
    }

    Since eg.h is included in eg.cpp, anything declared in eg.h as “file scope” will still be accessible in eg.cpp, even though it was in a different source file. This is because both source code files are compiled into the same object (*.o) file.

    “File scope” should really be “object scope”.

  • Jyot

    I am able to understand why i am getting
    100
    0
    instead of
    100
    111
    /****f1.cpp****/
    #include
    using namespace std;
    int xx;

    void call()
    {
    cout<<xx<<endl;

    }
    /****f2.cpp****/
    #include
    using namespace std;
    static int xx=100;
    extern void call();
    int main()
    {

    cout<<xx<<endl;
    {
    extern int xx;
    xx=111;
    call();
    }}

  • Jyot

    Is there any way to use xx defined in f1.cpp

  • MrFinn

    The C++ standard now defines an original and a revised meaning for the ‘auto’ keyword. Quote (MSDN):

    Starting with Visual C++ 2010, the auto keyword directs the compiler to deduce the type of a declared
    variable from its initialization expression. The previous meaning of the auto keyword as the specifier
    for the automatic storage-class is now an error.

    Check the MSDN for more and for compiler options to choose which behaviour you prefer.

You must be logged in to post a comment.