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
|
4.4 — Type conversion and casting
Index
4.2 — Global variables
[...] 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 [...]
[ 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 [...]
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).
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.
Will you please explain advantage of using static in global.and where the static is stored in ram or where
Also, since it is only declared once and not every time the function is called, it conserves memory. Right?
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.
Will you please explain advantage of using static in global.and where the static is stored in ram or where
Helped me a lot to understand the static keyword. The explanation is very clear and useful. Thanks.
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
They really thought of everything when they made C/++ programming language didn’t they? O_O
No they didn’t. Rather it evolved gradually as & when required by the mass.
It really has since the original K&R C programming
I have read everything so far, but to me they’ve missed some mathematical signs like the opposite of x^2, like ? (x) I don’t know how it’s called in english but in dutch it’s called: worteltrekken :P
But, thx anyway Alex ;)
In english it’s called square root. C++ doesn’t have a square root operator, like all other programming languages I know. But it does have a sqrt function in the “cmatch” library.
[...] 2007 Prev/Next Posts « 4.3 — File scope and the static keyword | Home | 4.5 — Enumerated types » Tuesday, June 19th, 2007 at 6:34 [...]
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!
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?
Yes these variables will be having global scope. If you are declaring variables in source1.h they should be preceded with “extern” keyword.
excellent tutorial for static variable concept.
thanks Alex.
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?
Brad -
The easiest way would be to write the variable to a file at the end of the program, then read it back in again when the program is next run.
Alex, thank you for this excellent tutorial! Great explanation of what is otherwise quite a tricky set of concepts.
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
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”.
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();
}}
Is there any way to use xx defined in f1.cpp
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.