I'm a little fuzzy on how variable access between .cpp files works. For instance:
main.cpp
int main()
{
int a = i;
return 0;
}
main2.cpp
int i;
This generates a compiler error on main.cpp, telling me there is no in i in existence. What difference then, does the "static" keyword do in this context? (I tried Googling for it, but most of the "static keyword" info pages talk about classes & functions)
main2.cpp
static int i;
Is it the same? Does it prevent extern int i being used to access i elsewhere? How does the use of anonymous namespaces differ in how variables are handled?
main2.cpp
namespace
{
int i;
}
To sum up:
Can variables be accessed between .cpp files? (aside from extern keyword)
How does the static keyword on a global variable affect things?
How do anonymous namespaces affect things differently?
In your first example, main2.cpp defines a global variable i, which could have been accessed by main.cpp if an extern declaration of i had appeared in that file. (Normally that extern declaration would come from a header file.) You got a compiler error because i had never been declared in main.cpp, which means the compiler assumes there is no such variable.
In your second example, main2.cpp defines a file scope variable i. File scope variables are distinct from globals, even if they happen to have the same name. If you had had an extern declaration of i in main.cpp in the second example, both files would have compiled successfully, but then you would have gotten a link error because no global variable i was defined.
If you renamed main2.cpp from the second example to main3.cpp, added an extern declaration of i to main.cpp, compiled all three and linked them all together, that would succeed; main.cpp and main2.cpp would share one variable named i, and main3.cpp would have its own entirely separate variable also named i.
This stuff is called linkage. Namespaces are almost entirely unrelated to linkage. However, the anonymous namespace is special. Defining a variable in an anonymous namespace is for all practical purposes the same as defining it with static -- it makes it a file scope variable. (If I remember correctly, there is a difference, but it only matters if you are doing complicated things with exported templates, and as exported templates are so little used that they're talking about deleting the feature from the C++ standard, you don't have to worry about it.)
The value of the anonymous namespace is that you can put a class definition inside it, and that makes all of the class's methods be file-local. (Only the class { ... } block has to be inside the namespace { ... } block to get this effect.) You can't do that any other way.
All global variables have some kind of linkage. extern linkage is required to name the same variable in different contexts between different files.
extern is the default. If you actually use extern in a variable declaration, it's treated as a reference to another file. Omit any linkage specifier to actually create the variable; this must happen in only one file.
extern int i; // i exists somewhere in some .cpp file.
int i; // ah! this is the file it exists in.
// (Although nothing special about that.)
static applied to a global (at namespace scope) makes it local to the file. You get the same effect from a private namespace, so static outside function or class scope is deprecated. Many still use it though.
The exception to the rule of static meaning file-local is in classes and inline functions. Class static members should more properly be called extern since the semantics are identical. It's ugly and confusing, but I guess Bjarne just wanted to eliminate extern as a keyword.
Inline functions can have the same definition among multiple .cpp files, so when one creates a static variable, the variable definition is shared as well.
yes, for example you can use static class variables
it makes variable local and persistent to compilation unit
anonymous namespace prevents collision between symbols. it is as if you create uniquely named namespace manually
Related
How do we make a variable global across over all .cpp files/modules of a (will-be) single binary, which is to be compiled and linked by g++ in a line?
even if it's been defined in main and has extern in var. to be included in every .cpp
extern int a_sample_var;
tried it for more a week only to fail,
.....: undefined reference to a_sample_var .....
Any generous guru helping me out?
extern int a_sample_var;
Tells the compiler: there is a int named a_simple_var defined somewhere else (think about the keyword extern: it's abbreviation for external, meaning "somewhere else"). Just leave a placeholder there and wait for the linker to find it!
Well if you do this in every cpp file (by including a header), then everyone is crying for the definition (by providing a declaration), but with no one to provide the definition. Be aware of the wording here, definition and declaration are different stuff.
In exactly one cpp file, you shall provide a definition of a_simple_var. Just simply remove the extern:
int a_sample_var; // Initialize with 0
or
int a_sample_var = 1; // Initialize with 1.
Those two are proper definitions.
Learning from this: By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.
But if I write this inside MyTools.h:
#ifndef _TOOLSIPLUG_
#define _TOOLSIPLUG_
typedef struct {
double LN20;
} S;
S tool;
#endif // !_TOOLSIPLUG_
and I include MyTools.h 3 times (from 3 different .cpp) it says that tool is already defined (at linker phase). Only if I change in:
extern S tool;
works. Isn't external default?
The declaration S tool; at namespace scope, does declare an extern linkage variable. It also defines it. And that's the problem, since you do that in three different translation units: you're saying to the linker that you have accidentally named three different global variables, of the same type, the same.
One way to achieve the effect you seem to desire, a single global shared variable declared in the header, is to do this:
inline auto tool_instance()
-> S&
{
static S the_tool; // One single instance shared in all units.
return the_tool;
}
static S& tool = tool_instance();
The function-accessing-a-local-static is called a Meyers' singleton, after Scott Meyers.
In C++17 and later you can also just declare an inline variable.
Note that global variables are considered Evil™. Quoting Wikipedia on that issue:
” The use of global variables makes software harder to read and understand. Since any code anywhere in the program can change the value of the variable at any time, understanding the use of the variable may entail understanding a large portion of the program. Global variables make separating code into reusable libraries more difficult. They can lead to problems of naming because a global variable defined in one file may conflict with the same name used for a global variable in another file (thus causing linking to fail). A local variable of the same name can shield the global variable from access, again leading to harder-to-understand code. The setting of a global variable can create side effects that are hard to locate and predict. The use of global variables makes it more difficult to isolate units of code for purposes of unit testing; thus they can directly contribute to lowering the quality of the code.
Disclaimer: code not touched by compiler's hands.
There's a difference between a declaration and a definition. extern int i; is a declaration: it says that there's a variable named i whose type is int, and extern implies that it will be defined somewhere else. int i;, on the other hand, is a definition of the variable i. When you write a definition, it tells the compiler to create that variable. If you have definitions of the same variable in more than one source file, you've got multiple definitions, and the compiler (well, in practice, the linker) should complain. That's why putting the definition S tool; in the header creates problems: each source file that #include's that header ends up defining tool, and the compiler rightly complains.
The difference between a const and a not-const definition is, as you say, that const int i = 3; defines a variable named i that is local to the file being compiled. There's no problem having the same definition in more than one source file, because those guys all have internal linkage, that is, they aren't visible outside the source file. When you don't have the const, for example, with int i = 3;, that also defines a variable named i, but it has external linkage, that it, it's visible outside the source file, and having the same definition in multiple files gives you that error. (technically, it's definitions of the same name that lead to problems; int i = 3; and double i = 3.0; in two different source files still are duplicate definitions).
By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.
That statement is still correct in your case.
In your MyTools.h, tool is external.
S tool; // define tool, external scope
In your cpp file, however, the extern keyword merely means that S is defined else where.
extern S tool; // declare tool
In a source file (not a header file), I have the habit of placing some state that only the implementation can work with:
//.cpp
namespace foo{
someType bar;
//... functions and objects that might use bar ...
}
Because bar is declared only in this cpp file, it is not possible for other code files to use it, correct?
Note, however, I have not placed static before it. In this case, though, that should make no difference?
Without static, is the only difference that this variable could be accessed (and actually set) by another code file if in some other file -- either header or cpp -- I had an extern declaration for the same variable name? (and of course, that this declaration was within a namespace of the same name)
Since I do not have any such extern declaration anywhere else in the code base, I gather that it makes no difference whether I mark this as static or not -- but I wanted to make sure that my thinking is correct.
You are correct, static on variables in namespace scope controls only the visibility of the variable from other translation units (internal vs. external linkage). Apart from that, the behavior of the variable is going to remain the same. For example, it storage class would remain static. The only difference is that without static a declaration
namespace foo{
extern someType bar;
...
}
from some other translation unit is going to "connect" to your bar variable, while with static the extern would fail at linking time.
In C++, I have been taught that a static linkage global variable is created when program starts and destroyed in the end of program. If the variable get destroyed in the end of the program (not file), I think there's definitely a way to use it in other files. I want to know how.
There are multiple meanings to static.
A variable declared at the file scope with static is visible only to functions in that file. You cannot use a static variable defined in one file from another file.
It sounds like you want a normal global variable. Just leave off the static.
"Local" variables, declared at at the function scope, have a default "auto" lifetime - their values persist only as long as the function executes, and once the functin returns, the value is gone. You can change this to live as long as the program with static.
If the variable is defined in a header, simply include the header and use it. If it's declared globally in a compilation module (i.e. .cpp file), then declare an extern version of it and use it. Note, this is not static which implies internal linkage which explicitly reduces the scope of the variable to a single compilation unit. This is global / external linkage.
E.g.
module1.cpp
int globalX = 5;
module2.h
extern int globalX;
module2.cpp
std::cout << globalX;
Been a while since I've done much C++, but I believe this should work.
How does the following example usage of extern specifer behave.
We have a global variable int x both in files one.c and two.c
We want to use these in three.c so have declared this variable in three.c as
extern int x;
What would happen when we compile and link these files?
My answer is: compilation of all these files should succeed, however the linker should flag an error at linking, due to multiple declarations of x.
Would there be any difference in behavior in C++ ?
Is these any way to refer to int x (in three.c) simultaneously from both files, in C and C++.
In C++, I guess we can use namespaces to acheive this. Right?
By default, global variables have external linkage, which means that they can be used by other source files (or "translation units"). If you instead declare your global variables with the static keyword, they will have internal linkage, meaning they will not be usable by other source files.
For variables with external linkage, you can't have multiple variables with the same name, or the linker will complain. You can have two variables with the same name, though, as long as at least one has internal linkage, and of course you can't reference both of them in the same source file.
An extern declaration is just saying to the compiler "here is the name of some variable with external linkage defined in another translation unit," allowing you to refer to that variable.
C++ is exactly the same, except for the addition of namespaces. If global variables are put inside a namespace, then they can have the same name without linker errors, provided they are in different namespaces. Of course, all references to those variables then have to either refer to the full name namespace::var_name, or use a using declaration to establish a local namespace context.
C++ also has anonymous namespaces, which are entirely equivalent to using the static keyword for global variables in C: all variables and functions declared inside an anonymous namespace have internal linkage.
So, to answer your original question, you are right -- compilation would succeed, but linking would fail, due to multiple definitions of the variable x with external linkage (specifically, from the translation units one.c and two.c).
From three.c, there is no way to refer simultaneously to both variables x. You'll need to rename x in one or both modules, or switch to C++ and put at least one x inside a namespace.
In C, you could do this:
// one.c
static int x;
int *one_x = &x;
// two.c
static int x;
int *two_x = &x;
// three.c
extern int *one_x;
extern int *two_x;
Now you can refer unambiguously to the x in file one.c or the x in file two.c from the file three.c.
However, this might be a bit more effort than it's worth. Perhaps you should be coming up with more descriptive names for your global variables instead of toying around with theoretical ways to circumvent C's single global namespace.
To avoid generating duplicate symbols, you should declare extern int x; in a single header file (a .h file), and then have all .c files which will use x #include that header file, and define or initialize int x; in one of the .c files.
You might be interested by the answers to this question.
Summary: the linker may or may not fail to link the file. It depends on the initialization of the variable. It will definitely fail if the variable has different initializations in different files.
Remember that you can NOT extern a global static variable.. !!