I have a config.h file with a bunch of constants.
in main.cpp, it sets one of the constants to some value, and then calls a function in util.cpp.
util.cpp also has config.h included, but the variable set by main.cpp does not have the same value.
Code:
config.h:
static int MAX_NUMBER_OF_TRAINING_DATA = 1000;
main.cpp (main):
else if (strcmp(argv[i], "-mTrnData") == 0)
{
MAX_NUMBER_OF_TRAINING_DATA = atoi(argv[i + 1]);
cout << "Number of data sets to be generated: " << MAX_NUMBER_OF_TRAINING_DATA << "\n\n";
// prints what I tell it
}
and in utils.cpp
cout << "Number of data sets generated: " << MAX_NUMBER_OF_TRAINING_DATA << "\n\n";
// prints the default value (in this case, 1000)
So, how do I fix this so that I can have my config.h file of constants be remembered throughout my cpp files?
In Java, you can do Config.NAME_OF_CONSTANT , so, if there is a way to do that in C++, that would be most grand.
I know constants aren't supposed to change, but the only time they do change is in main() when reading in the arguments from the running the program... after that they don't change.
Each translation unit receives its own copy of static data.
The easiest way to verify this is to print the address of MAX_NUMBER_OF_TRAINING_DATA in both units - it will be different. To avoid it, declare it extern in the header and define it once in one unit, for example in main.cpp.
Apart from that is it evil to have such global variables (whose naming scheme even suggests that we're talking about constants!). You might consider to refactor the code, for example use a getter GetMaxNumberOfTrainingData() to make the value available while keeping write access to it restricted to a single unit.
A non-const static variable at namespace scope in a header file is
almost certainly an error. You get an instance of the variable for each
file that includes the file. If you want to use the same variable in
several different translation units, declare it extern (and without
the initializer) in the header, and then define it (without the
extern, although you can also use the extern if there is an
initializer) in a single source file.
A static variable has a "file scope" by definition. So by declaring it in a header file, every .c file that includes it gets its own variable. They have nothing to do with each other.
You should genereally never declare variables in header files. If you need a variable in multiple modules, declare it in one file and add them as extern in all other files you need it.
From a design point of view, you should switch to a Configuration or Option object.
Each class would depend on an instance of this object to be provided, and you could have different initializations routines: from a file, from command line, etc...
Better yet, you would avoid the global variables!
Related
I am new in programming in C, so I am trying many different things to try and familiarize myself with the language.
I wrote the following:
File q7a.h:
static int err_code = 3;
void printErrCode(void);
File q7a.c:
#include <stdio.h>
#include "q7a.h"
void printErrCode(void)
{
printf ("%d\n", err_code);
}
File q7main.c:
#include "q7a.h"
int main(void)
{
err_code = 5;
printErrCode();
return 0;
}
I then ran the following in the makefile (I am using a Linux OS)
gcc –Wall –c q7a.c –o q7a.o
gcc –Wall –c q7main.c –o q7main.o
gcc q7main.o q7a.o –o q7
the output is 3.
Why is this happening?
If you initialize a static variable (in fact any variable) in the header file, so if 2 files include the same header file (in this case q7.c and q7main.c) the linker is meant to give an error for defining twice the same var?
And why isn't the value 5 inserted into the static var (after all it is static and global)?
Thanks for the help.
static means that the variable is only used within your compilation unit and will not be exposed to the linker, so if you have a static int in a header file and include it from two separate .c files, you will have two discrete copies of that int, which is most likely not at all what you want.
Instead, you might consider extern int, and choose one .c file that actually defines it (i.e. just int err_code=3).
When you declared a variable as a static it has only scope within a file ie.., it can be accessed only within a file.
When you declare a static variable in a header file and include this header file in two .c file, then you are creating two different
memory for two different ".c" files
When you print err_code directly in the Main function you would see its value as 5 instead 3,
but you are calling a function printErrCode which is defined in a different file "q7a.c" for which err_code has a different memory location
in which err_code memory is still 3 and it not updated and that is why you are getting the value as 3 instead of 5.
Since two memory is created and err_code is considered as two different variables having different memory with different file scope you will not see any linking errors.
The static variables do not have external linkage which means they cannot be accessed outside the translation unit in which they are being defined. So in your case when q7.h is #include'ed in both translations units q7a.c and q7main.c ... two different copies exists in their corresponding .o files. That is why linker does not report error becuase both copies are not seen by linker while doing external symbol linkage.
While doing small research came to know that we can declare variable in Header file but in one of the source file includes that should have definition for that variable.
Instead if we define a variable in header file. in the source files where this header file included, definitions will be created which causes multiple definitions.
A static variable should be declared with in the file where we use it shouldn't be exposed to header file.
Hope I am giving right information. If I am wrong feel free to correct my statements in your comments.
I am new in programming in C, so I am trying many different things to try and familiarize myself with the language.
I wrote the following:
File q7a.h:
static int err_code = 3;
void printErrCode(void);
File q7a.c:
#include <stdio.h>
#include "q7a.h"
void printErrCode(void)
{
printf ("%d\n", err_code);
}
File q7main.c:
#include "q7a.h"
int main(void)
{
err_code = 5;
printErrCode();
return 0;
}
I then ran the following in the makefile (I am using a Linux OS)
gcc –Wall –c q7a.c –o q7a.o
gcc –Wall –c q7main.c –o q7main.o
gcc q7main.o q7a.o –o q7
the output is 3.
Why is this happening?
If you initialize a static variable (in fact any variable) in the header file, so if 2 files include the same header file (in this case q7.c and q7main.c) the linker is meant to give an error for defining twice the same var?
And why isn't the value 5 inserted into the static var (after all it is static and global)?
Thanks for the help.
static means that the variable is only used within your compilation unit and will not be exposed to the linker, so if you have a static int in a header file and include it from two separate .c files, you will have two discrete copies of that int, which is most likely not at all what you want.
Instead, you might consider extern int, and choose one .c file that actually defines it (i.e. just int err_code=3).
When you declared a variable as a static it has only scope within a file ie.., it can be accessed only within a file.
When you declare a static variable in a header file and include this header file in two .c file, then you are creating two different
memory for two different ".c" files
When you print err_code directly in the Main function you would see its value as 5 instead 3,
but you are calling a function printErrCode which is defined in a different file "q7a.c" for which err_code has a different memory location
in which err_code memory is still 3 and it not updated and that is why you are getting the value as 3 instead of 5.
Since two memory is created and err_code is considered as two different variables having different memory with different file scope you will not see any linking errors.
The static variables do not have external linkage which means they cannot be accessed outside the translation unit in which they are being defined. So in your case when q7.h is #include'ed in both translations units q7a.c and q7main.c ... two different copies exists in their corresponding .o files. That is why linker does not report error becuase both copies are not seen by linker while doing external symbol linkage.
While doing small research came to know that we can declare variable in Header file but in one of the source file includes that should have definition for that variable.
Instead if we define a variable in header file. in the source files where this header file included, definitions will be created which causes multiple definitions.
A static variable should be declared with in the file where we use it shouldn't be exposed to header file.
Hope I am giving right information. If I am wrong feel free to correct my statements in your comments.
I am trying to create bunch of void methods and call them later in program.
I will demonstrate the code ahead to help better understand my issue.
.h file
static float sfloat;
namespace someNamespace
{
static void foo();
}
.cpp file
void someNamespace::foo(){cout<<sfloat<<endl}
above code is simpler version of class that I was working on.
I initialize sfloat in other .cpp file
otherFile.cpp
void initializeAndUseFoo(){sfloat = 5; someNamespace::foo();}
As far as my understanding goes, I expect foo to print out 5 but it prints out 0 instead.
This behavior occurs across all other static variables that I have as well(pointer included). It seemed that somehow the variables inside the function are never initialized as the value I assign.
However if I call out "sfloat" not through the function then I can call it out properly.(if I just print it out on console with just
cout<<"just print it not through the function : " <<sfloat<<endl;
then it is indeed 5
Thank you for reading.
A global static variable is static within one compilation unit. If you make another compilation unit, it will have a separate copy of that static variable.
This SO question explains what a compilation unit is in C++.
Since your variable is static and global in the same time, there will be a single instance of it in it's compilation unit. If you want to access that exact variable from another file, you will have to use the extern keyword. Without it, a new copy of that variable will be created in each compilation unit. You can find some information here, for example.
That's not a class, it's a namespace. static inside the namespace or at global scope gives methods and variables internal linkage. That means a copy of each will be available for each translation unit.
Because you modify (not initialize) sfloat in otherFile.cpp, only that version of the variable is modified. The original, initialized in .cpp file, retains the same value (which is the version printed by someNamespace::foo().
Take for example:
// myheader.h
static int myStaticVar = 0;
// If we remove 'static' the compiler will throw linker error.
void DoStuff();
// and myheader.cpp, and main.cpp; etc
This is how I would explain it:
Static variables do not have external linkage, and when we compile
without 'static' we are "including" the static variable (which is
global here) in every file, which create duplicates and linker will
throw an error since multiple declaration is not allowed.
Is there any better way to explain this? Thanks.
PS: Are we suppose to have static variables (not talking about members) in header file?
Why can't a non-static variable reside in a header file?
Because it breaks the One Definition Rule(ODR).
When you include the header file containing a non-static variable, the declaration of the variable gets pasted in each source file where it is included. Thus you end up having more than one definition of a variable in same Translation Unit, this violates the ODR and hence the linker will give you linking errors.
How to explain static variables declared in header files?
When you declare a static variable in an header file, an copy of the variable gets created in each Translation Unit where the header file is included.
Declaring a static variable in header file will not give you multiple definition erros but it does not acheive your purpose of having a global variable whose value is shared accross all files which access it.
You may think that since you are using a global static variable its value will be retained accross different files, but as mentioned above each Translation Unit has its own copy of the variable and it does not acheive what you think you are acheiving.
Are we suppose to have static variables (not talking about members) in header file?
No,Never!
How do you declare and define global variables?
You need to use extern keyword.
Add the extern declaration of the variable in an header file. The header should be included by the one source file that defines the variable and by all the source files that reference the variable. Only one source file should define the variable. Also only one header file should declare the variable.
filename.h
extern int gVariable; /* Declaration */
file1.cpp
#include "filename.h"
/* Definition */
int gVariable = 37;
void doSomething(void)
{
return gVariable++;
}
file2.cpp
#include "filename.h"
#include <stdio.h>
void doSomethingWithGlobal(void)
{
printf("Global variable: %d\n", gVariable++);
}
First, read this answer to a similar question.
To complement the answer based on your question, here goes:
When you #include a file (any file, .h files is a common convention), it almost basically just copy-pastes it in your code. If you have non-static variable in the header file and you include it in two source files, the variable gets copy-pasted in both source files and well you get a link error as I explained in the answer I told you to read above.
If you want to share a global variable across many source files, you should do this:
In only one of your source files:
type global_var = default_value;
In the header file:
extern type global_var;
So, this way, all the source files see there is going to be a global_var somewhere in the bunch of source files. Only one of the source files actually contains that variable and when linking happens, all the source files would be referring to that one instance of global_var
The header file (.h) tells you (declares) what the definition file (.cpp) will do.
For a metaphor - a header file is like to telling a lot of friends that you are going to do something, but in reality you are going to do it once.
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.