I would like to know what is the difference between static variables in a header file vs declared in a class. When static variable is declared in a header file is its scope limited to .h file or across all units. Also generally static variable is initialized in .cpp file when declared in a class right? So that does mean static variable scope is limited to 2 compilation units?
Excuse me when I answer your questions out-of-order, it makes it easier to understand this way.
When static variable is declared in a header file is its scope limited to .h file or across all units.
There is no such thing as a "header file scope". The header file gets included into source files. The translation unit is the source file including the text from the header files. Whatever you write in a header file gets copied into each including source file.
As such, a static variable declared in a header file is like a static variable in each individual source file.
Since declaring a variable static this way means internal linkage, every translation unit #includeing your header file gets its own, individual variable (which is not visible outside your translation unit). This is usually not what you want.
I would like to know what is the difference between static variables in a header file vs declared in a class.
In a class declaration, static means that all instances of the class share this member variable; i.e., you might have hundreds of objects of this type, but whenever one of these objects refers to the static (or "class") variable, it's the same value for all objects. You could think of it as a "class global".
Also generally static variable is initialized in .cpp file when declared in a class right ?
Yes, one (and only one) translation unit must initialize the class variable.
So that does mean static variable scope is limited to 2 compilation units ?
As I said:
A header is not a compilation unit,
static means completely different things depending on context.
Global static limits scope to the translation unit. Class static means global to all instances.
PS: Check the last paragraph of Chubsdad's answer, about how you shouldn't use static in C++ for indicating internal linkage, but anonymous namespaces. (Because he's right. ;-) )
Static variable in a header file:
say 'common.h' has
static int zzz;
This variable 'zzz' has internal linkage (This same variable can not be accessed in other translation units). Each translation unit which includes 'common.h' has it's own unique object of name 'zzz'.
Static variable in a class:
Static variable in a class is not a part of the subobject of the class. There is only one copy of a static data member shared by all the objects of the class.
$9.4.2/6 - "Static data members of a
class in namespace scope have external
linkage (3.5).A local class shall not
have static data members."
So let's say 'myclass.h' has
struct myclass{
static int zzz; // this is only a declaration
};
and myclass.cpp has
#include "myclass.h"
int myclass::zzz = 0 // this is a definition,
// should be done once and only once
and "hisclass.cpp" has
#include "myclass.h"
void f(){myclass::zzz = 2;} // myclass::zzz is always the same in any
// translation unit
and "ourclass.cpp" has
#include "myclass.h"
void g(){myclass::zzz = 2;} // myclass::zzz is always the same in any
// translation unit
So, class static members are not limited to only 2 translation units. They need to be defined only once in any one of the translation units.
Note: usage of 'static' to declare
file scope variable is deprecated and
unnamed namespace is a superior
alternate
A static variable declared in a header file outside of the class would be file-scoped in every .c file which includes the header. That means separate copy of a variable with same name is accessible in each of the .c files where you include the header file.
A static class variable on the other hand is class-scoped and the same static variable is available to every compilation unit that includes the header containing the class with static variable.
Related
I've actually never tried it until now.
Is it possible to have statics just in namespace scope without a class?
Why not?
namespace MyNamespace
{
static int a;
}
assign something, somewhere else....
Annex D (Compatibility features) [C++03]
D2: The use of the static keyword is deprecated when declaring objects in namespace scope.
static variable at namespace scope (global or otherwise) has internal linkage. That means, it cannot be accessed from other translation units. It is internal to the translation unit in which it is declared.
update
When you declare a variable as static, it means that its scope is limited to the given translation unit only. Without static the scope is global.
When you declare a variable as static inside a .h file (within or without namespace; doesn't matter), and include that header file in various .cpp files, the static variable becomes locally scoped to each of the .cpp files.
So now, every .cpp file that includes that header will have its own copy of that variable.
Without the static keyword the compiler will generate only one copy of that variable, so as soon as you include the header file in multiple .cpp files the linker will complain about multiple definitions.
static keyword keeps the scope of a global variable limited to that translation unit.
If I use static int x in a .h file and include that .h file every other file, won't they all belong to the same translation unit?
Then, won't x be visible everywhere?
So what is the role of static now?
Also, is there any use of static const int x ,where x is a global variable?
Aren't all const global variables static by default?
And is a const variable's scope limited to the TU even if it confined in a for loop in the file?
If you write
static const int x
in an .h file then every translation unit that #include-s this .h will have its own private variable x.
If you want to have 1 global variable visible to everyone you should write
extern const int x;
in the .h file and
const int x = ...;
in one of the .cpp files.
If you want to have a static const int visible to just one translation unit - don't mention it in the .h files at all.
If I use static int x in a .h file and include that .h file every
other file, won't they all belong to the same translation unit?
If you declare something as static (not inside a class, for class static keyword has a different semantic), that static variable cannot be seen outside its TU. So putting it in the header file will cause each TU including that header to have a different private copy of that static variable.
And is a const variable's scope limited to the TU even if it confined
in a for loop in the file?
NO. Even for a static const value, the scope is determined by it's declaration. So the scope will be limited by your for brackets.
you will end up will private copies of that variable per translation, which will result in bloat if you put it there. it would also make no sense to have to random copies all over the place. no it's not ok.
you can declare a const int in a namespace block; that's ok.
The observable difference for variables that are const qualified is that in the static version you will get one copy per translation unit and so address comparisons of two such copies may fail.
If you never use the address of your const variable any modern compiler should be able to just use the value and optimize the variable itself out. In such a case a static const-qualified variable is completely fine.
Basically, each source file together with all included header files is a single translation unit. So If you have a static variable in a header file then it will be unique in each source file (translation unit) the header file is included in.
"static global" doesn't make sense, they are in a way each other's opposites.
The term "global" is often misused to describe a variable declared outside any function at file scope. But rather, a global variable is one with external linkage, that can be accessed by any file in the project - hence global.
The opposite of external linkage is internal linkage, which means that a variable can only get accessed by the translation unit where it is declared. Translation unit meaning one .c file and all the headers included by it (recursively).
static is a guarantee that a variable gets internal linkage. Thus other translation will not be able to access it or declare extern variables referring to it.
What happens if you declare a static variable in a header file is that more than one translation unit will get a separate variable with that name. The code will compile fine, although clever linkers will notice this and give a linker error. These kind of linker errors are often non-descriptive and hard to track down.
This leads us to the following best practices:
Never declare any variables inside a header file, as this often creates subtle bugs and linker errors.
To prevent such bugs, always surround all header files with "header guards":
#ifndef MYHEADER_H
#define MYHEADER_H
/* contents of header */
#endif
All variables declared at file scope should be declared static, for the purpose of private encapsulation and to reduce namespace clutter. Similarly, extern should be avoided, as it leads to bad design and spaghetti programming.
Suppose you have a static global variable in your header file, and you use this variable in your main.cpp.
// header.h
static int variableOne = 100;
//main.cpp
.
.
cout << variableOne << endl;
Will main.cpp get its own copy of variableOne (although the value is still 100...)? Or am I mixing this concept with extern (I know that extern tells the compiler that variableOne is defined elsewhere in the project...)
Thank you.
If you declare a static variable in an header file then a copy of that variable will be created in each translation unit where you include the header file.
So Never declare a static variable in Header File.
Also, C++03 standard: 7.3.1.1/2 says:
The use of the static keyword is deprecated when declaring objects in a namespace scope, the
unnamed-namespace provides a superior alternative.
C++03 standard: 7.3.1.1/1 says:
"[a]lthough entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit."
In simple words, an unnamed namespace restricts the visibility of its members to the scope of the translation unit by means of name mangling and avoids the problems faced as while using static keyword.
Also, You cannot use keywords static and extern together on a variable because both aim to achieve mutually exclusive behaviors.
In this case, each compilation module will get it's own copy of the variable.
If you use extern, there will only be one copy. But you are only allowed to initialize it in one module.
In other words, if you just replace static with extern in your example, it won't compile because it's being initialized in every module that includes that header.
1. What does it mean #include
When you write #include "header.h" the compiler is basically just copying the whole content of the file instead of that line. In C++ an header file has no semantic meaning, it's just used for textual substitution.
So if you have
---- header.h ----
static int variableOne = 100;
---- main.cpp ----
#include "header.h"
...
std::cout << variableOne << std::endl;
for the compiler is exactly the same as
---- main.cpp ----
static int variableOne = 100;
...
std::cout << variableOne << std::endl;
2. What does it mean static in that context
A static variable is like a global for the lifetime (i.e. it's constructed before main starts and it's destroyed after main terminates) but is only visible inside the translation unit that defines it. So you can have the same static variable name used in different translation units and all those variables are distinct (each translation unit will see its own static variable).
3. What happens when you put a static variable declaration in an header?
The net result is that every translation unit that will include that header will get its own static variable with that name because it's exactly the same as if the translation unit defined a static variable in the .cpp and not in the header file.
The name will be the same for all of them but they will be different variables. Of course if the header file declares and initializes the variable then the initial value will be the same, but all those variables will be distinct and if for example one translation unit changes that variable, the change will not be seen by other translation units.
Each source file would get their own independent copy of variableOne.
The last use of static is as a global variable inside a file of code.
In this case, the use of static indicates that source code in other
files that are part of the project cannot access the variable. Only
code inside the single file can see the variable.
Source
If you use extern all your source files will reference the same variable, but you won't be able to initialize it in the header. You would have to add an initialization to one of the source files.
static variables in namespace scope are not external, and as such you would get a copy of the static variable for each 'translation unit' in the project. This technique has been obsoleted since C++03, and the recommended way to do it is now enclosing the variable within an unnamed namespace.
class X {
static int i;
// some other function, variable declaration, cons, dest
};
int X :: i ; **(!)**
Why must I write that (!) line, always ?
If I dont write, compiler cannot complete internal linkage, and so it gives ( I assume ) linker error. Why ?
This is known as the One Definition Rule. Each global object (technically, each object with external linkage) must be defined in exactly one source file (technically, in one translation unit). However, it can be declared as many times as you like.
Typically, a class definition will be in a header file, which might be included by many source files. So any static members can't be defined there, only declared, otherwise there will be multiple definitions. You must separately define the static members in exactly one source file, in order for the linker to find exactly one definition. That is what the line marked (!) does.
Because that is how static members work. They exist apart from the instances directly in the class.
You can't define them inside the class, because then you would have multiple definitions for every implementation file that is using your class.
Therefore you need to choose one implementation file that will actually define the static member.
The static variable must be defined (as opposed to declared) in a TU (i.e. a cpp file).
If it's only declared and not defined, no storage is allocated for it, so the linker can't find it.
static int i; is a declaration, i.e. tells to the compiler that in some translation unit (=>.cpp file) such static field will be actually defined. It is needed to let the compiler know that such variable exists and to let you use it in each translation unit where it's declared.
int X :: i;, instead, is a definition, it tells to the compiler to actually provide the space for that variable. It must stay in a single .cpp, otherwise each translation unit would provide some space for it on its own (and the linker would complain).
It's the exact same reason why for globals you need an extern declaration in every file that needs to use it (usually put in a header) and a normal definition in the single .cpp that defines it.
C++ makes a clear distinction between declaration and definition. You need to tell the compiler two things:
The data type of the variable: declaration.
The place in memory on where you want your variable to be located: definition.
This is usually done in one single step, ie a local int variable:
void f() {
int x; // Declaration and definition.
}
Since a .hpp header file can be included on many .cpp files, your (!) line must reside on a single specific .cpp, usually outside any header file.
Static class members are shared among all class instances (there is one and only place in memory where such variable resides) and therefore static int i; inside class declaration represents variable declaration only - and you need to allocate memory for that variable somewhere - you need to define it - which is done in implementation file with int X::i;
The class definition only defines the member, but it must exist in a single compilation unit (i.e. a .cpp file).
You could say it is part of the "one-definition rule".
I've run into an interesting problem in an AI project of mine. I'm trying to format some debug text and something strange is happening. Here's a block of code:
float ratio = 1.0f / TIME_MOD;
TIME_MOD is a static float, declared in a separate file. This value is modified based off of user input in another class (I have verified that the value is changed while still debugging within the scope of the "input" function), but whenever I try to divide by it in my outer loop I get the same number. (1 divided by the initial value of TIME_MOD).
Am I missing something regarding static variables and file scope?
I think there is some confusion with the word "static". We have a keyword static that does different things in different contexts and we use the word "static" to name one of three classes of "storage durations". In some contexts static does not control the storage duration of objects but only "linkage" which is probably the main reason for the confusion.
Storage durations
A storage duration is a property of an object.
The memory of an object with static storage duration is allocated once and once only. Initialization depends on the kind of object and where it is defined. Once it is initialized, it generally stays alive until the execution of main ends. Objects you declare and define at global/namespace scope always have a static storage duration.
Objects with automatic storage duration can only be defined inside a block in functions. Such an object is created when execution reaches the definition. This can happen multiple times (recursion) which creates multiple objects. When execution leaves the block the objects are automatically destroyed.
Dynamically allocated objects have a dynamic storage duration. In this case the user controls the life-time of the objects via new, new[], delete, delete[] etc.
Linkage
Internal vs external linkage is about visibility of names across translation units. If you declare something with external linkage you introduce a name that can be used in other translation units as well to refer to the same entity as long as those other TUs contain the proper declaration (usually contained in a header file). If you define something with internal linkage you can't access it from another translation unit by name. You can even define multiple entities with the same name (one per TU) as long as you have no more than one with external linkage.
The keyword "static"
The effect of static depends on the context:
If you declare or define an object at global/namespace scope it is always an object with "static storage duration". The use of the keyword static at global/namespace scope doesn't affect the storage duration at all. Instead, it affects linkage. It declares the entity -- which might be a function as well -- to have internal linkage. So, the storage class specifier has been "misused" to do something completely different: enforce internal linkage. It's sort of the opposite of extern in this context. In C++ you can achieve the same effect with an anonymous namespace. You are encouraged to prefer anonymous namespaces over static to "minimize confusion".
static at class scope can be used to declare objects with static storage duration in the scope of the class. There's only one such variable and not one for each object.
static at function scope can be used to declare objects with static storage duration that is lazily initialized
If you say "static variable" it's not clear what you mean exactly. Do you refer to the "static storage duration" or "internal linkage"?
If you want to share a "global" variable across translation units you have to declare it in a header file as an entity with external linkage and define it in exactly one translation unit. Note that the keyword static is not used:
// myheader.hpp
extern int k; // declaring an int variable with external linkage
// foo.cpp
#include "myheader.hpp"
int k; // defining an int variable with external linkage
// bar.cpp
#include "myheader.hpp"
int main() {
return k;
}
A static variable only exists within the current compilation unit. Remove the static from its definition and change it to "volatile" (Though this assumes you are using multiple threads, if not you needn't use volatile) and all should be fine.
Edit: By your answer here I am assuming you have some code as follows.
A.cpp:
static float TIME_MOD = <some value>;
B.CPP:
static float TIME_MOD = <some value>;
If you are doing this then TIME_MOD exists in 2 places and this is the source of your problems. You need to re-write the code more like this.
A.cpp:
float TIME_MOD = <some value>;
B.CPP (And C.CPP, D.CPP etc):
extern float TIME_MOD;
And then use TIME_MOD as usual. This tells the compiler that TIME_MOD is somewhere else and not to worry about not knowing what it contains. The linker will then go through and "link" this floating TIME_MOD definition to the correct definition.
Its also worth pointing out that it is probably work having the "extern float TIME_MOD;" in a header file somewhere and including it in any CPP files you need it in. Still keep the actual definition (ie the non extern'd definition) in one, and only one, file.
This would certainly explain the fact that I thought you were extern'ing a static (which i thought was impossible).
You could change the static variable to a #define, and set a member variable in a singleton equal to it. Modifications and accesses would apply to the singleton's member variable.
Static variables are linked internally. you can not access a static variable defined in some other source file.
The situation you are falling into may happen in case when you have defined the static variable TIME_MOD in some header file.Include the same header file in both the input and ratio source files, hence both files have a private copy of the variable TIME_MOD,
Now the input module changes the TIME_MOD value, but it modifies its own private copy so the value in ratio file remains unchanged and hence your behavior.
Now if that is the case you do not need a static TIME_MOD, and to resolve name conflicts you may like to use namespaces.
I guess you declared this variable in header file as: static float TIME_MOD;
And included this file in cpps. By doing this you effectively created separate instances of same named variable in each compilation unit.
You should change declaration to: extern float TIME_MOD;
And define variable in one of cpps: float TIME_MOD = 0;