The C++11 standard give the code snippet below (I deleted unrelated code) and said the name i have external linkage. (clause 3.5.6)
static int i = 0; // #1
void g() {
extern int i; // #3 external linkage
}
Why do they do this? Did I misunderstand something? The two i refer to the same object in vs2012. And when I use i somewhere else, i got an unresolved external error. I have no idea whether vs2012 support this feature or not.
Edit:
I think VS2012 is doing the right thing. The i in #3 only need to refers to an i that has a linkage. If the compiler can't find one, than the i should be defined in other translation unit. So the two i should refer to the same object in the code snippet above.
The quote from the standard:
If there is a visible declaration of an entity with linkage having the
same name and type, ignoring entities declared outside the innermost
enclosing namespace scope, the block scope declaration declares that
same entity and receives the linkage of the previous declaration. if
no matching entity is found, the block scope entity receives external
linkage.
But why people need this feature?
#3 is only a declaration; it states that a variable called i exists somewhere in the program, with external linkage, but does not define that variable. The declaration allows you to use that, rather than the static variable from #1, within the scope of g.
You will also need to define it, in the namespace that contains g. In this case, it will have to be in a different translation unit, so that it doesn't conflict with the static variable with the same name.
To be clear, there are two different variables called i here, as explained in the paragraph following the example. #1 is defined here; #3 is only declared, and needs a separate definition.
static int i = 0; // #1
void g() {
extern int i; // #3 external linkage
}
The first static i is a declaration and is visible only in the current source file.
extern int i;
tells the compiler I don't mean this static i but another i defined somewhere else. If you haven't defined it somewhere else (in another translation unit) you will get the undefined reference.
And this doesn't break the ODR because this (the static) i is static (visible only in this unit).
extern int i;
Promises compiler I will give you an int i.
The static int i=0; is not that promised variable, and you have to declare a int i somewhere else visible to that extern variable declaration.
In other words extern int i; and static int i=0; are two irrelevant variables.
Related
Please refer to the following code that is in the same translation unit:
static int global_var; // file scope in C and global namespace scope in C++
// internal linkage
void f(void)
{
static int local_var; // block scope in C and local scope in C++
// no linkage
}
My understanding is this:
I can refer to global_var from anywhere in the translation unit because it has global scope.
I can refer to local_var only inside function f because it has local scope.
My questions:
What is the difference beteen the two variables, in relation to linkage?
Can you provide one example where internal and no linkage makes a difference, and the difference is derived not only from scope?
EDIT
After the answer and comments of James Kanze, I am now able to construct an example that shows the difference between the internal and no linkage attributes:
static int i; // definition
// static storage
// internal linkage
void f(void)
{
extern int i; // declaration
// refers to the static i at file scope
// note that even though the specifier is extern
// its linkage is intern (this is legal in both C/C++)
{
int i; // definition
// automatic storage
// no linkage
}
}
Some articles that do a good job at explaining the concepts involved:
- Scope regions in C and C++
- Storage class specifiers and storage duration
- Linkage in C and C++
First: in addition to type, variables have three other
characteristics: linkage, scope and lifetime. All four
attributes are sort of orthogonal, but linked in the way they
are expressed in the language, and do interact in some ways.
With regards to linkage: linkage really affects the symbol which
is being declared, and not the object itself. If there is no
linkage, all declarations of the symbol bind to different
objects, e.g.:
int
func()
{
int i;
{
int i;
}
}
The symbol i has no linkage, and the two symbols i are bound
to two different entities. Generally speaking, local variables
(variables declared at block scope) and function arguments have
no linkage, regardless of type and lifetime.
Internal and external linkage are similar, in that repeated
declarations of the symbol bind to the same entity: internal
linkage binds only within the translation unit, external accross
the entire program. So given:
static int i; // internal linkage...
in several translation units, the i binds to a separate entity
in each translation unit. Without the static, you have external
linkage, and all of the i bind to the same entity.
Note that this only holds at namespace scope; all entities
which are members of a non-local class have external linkage.
And that type has an impact: variables which are const
implicitly have internal linkage:
int const i = 42; // same as static int const i...
extern int const j = 42; // external linkage.
Finally, all declarations which bind to the same entity must
declare it to have the same type. If you violate this rule in
a single translation unit (e.g.:
extern int i;
// ...
double i;
in the same namespace scope), then the compiler should complain.
If the two declarations are in different translation units,
however, it is undefined behavior, and who knows what will
happen. (In theory, the linker could complain, but most don't.)
EDIT:
One additional point: linkage is determined by the first
declaration which can refer to the entity. So if I write:
static int i;
void
func()
{
extern int i;
}
Both i refer to the same entity, which has internal linkage.
(Why one would ever write the second declaration is beyond me,
but it is legal.)
Generally static variables have internal linkage. You can't access the static variable or function in another file(in multiple file compilation situations), because its scope limited within this file(Internal linkage).
Normally auto and register variables have no linkage.
As i said above auto and register variables have no linkage. You can't declare these variables in global scope. static variables has internal linkage, scope is based on declaration, but not possible to access in another file. extern variables has external linkage, its possible to access these variables in another file.
For more reference Storage classes
global_var could be accessed from void g() in the same compilation unit, that is the difference.
I am a student and I am confused about global and file scope variables in C and C++.
Is there any difference in both perspectives? If yes, please explain in detail.
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.
It is perhaps clearer to illustrate file (or more precisely, translation unit)-scope vs global scope when there are actually multiple translation units...
Take 2 files (each being it's own translation unit, since they don't include each other)
other.cpp
float global_var = 1.0f;
static float static_var = 2.0f;
main.cpp
#include <cstdio>
extern float global_var;
//extern float static_var; // compilation error - undefined reference to 'static_var'
int main(int argc, char** argv)
{
printf("%f\n", global_var);
}
Hence the difference is clear.
A name has file scope if the identifier's declaration appears outside of any block. A name with file scope and internal linkage is visible from the point where it is declared to the end of the translation unit.
Global scope or global namespace scope is the outermost namespace scope of a program, in which objects, functions, types and templates can be defined. A name has global namespace scope if the identifier's declaration appears outside of all blocks, namespaces, and classes.
Example:
static int nValue; // file scoped variable
float fValue; // global variable
int main()
{
double dValue; // local variable
}
Read more here.
File scope: Any name declared outside all blocks or classes has file scope. It is accessible anywhere in the translation unit after its declaration. Names with file scope that do not declare static objects are often called global names.
In C++, file scope is also known as namespace scope.
Read this carefully now.
You use those #include<'...'.h> statements at the top of your program/code.
What you actually are doing there is telling the computer to refer to the functions prewritten in those *h*eader files.That is, those functions have file scope.You donot write the code of printf scanf and functions like these cauz they are somewhere in header files.
Variables declared outside a function have "file scope," meaning they are visible within the file. Variables declared with file scope are visible between their declaration and the end of the compilation unit (.c file) and they implicitly have external linkage and are thus visible to not only the .c file or compilation unit containing their declarations but also to every other compilation unit that is linked to form the complete program.
Global variables can, as the name suggests, be considered to be accessible globally(everywhere)
extern is a storage class in C. How exactly does it work? The output of the code given below is 20. How is this the output?
#include <stdio.h>
int main()
{
extern int a;
printf("%d", a);
return 0;
}
int a=20;
It means three things:
The variable has external linkage, and is accessible from anywhere in the program;
It has static storage duration, so its lifetime is that of the program (more or less); and
The declaration is just a declaration, not a definition. The variable must also be defined somewhere (either without the extern, or with an initialiser, or in your case, both).
Specifically, your extern int a; declares that the variable exists, but doesn't define it at that point. At this point, you can use it, and the linker will make sure your use refers to the definition. Then you have the required definition, int a=20; at the end, so all is well.
extern in this case indicates that the symbol a is defined in a different location, such as a different module. So the linker looks for a symbol with the same name in all of the modules that are linked, and if one exists then it sets the address to your local variable a with the address to the externally defined variable. Since you have another a defined outside of your main() function, the a inside your main() function is (basically) the same variable as the one outside.
Since the global a is initialized before the main function executes, the value is 20 by the time you access it.
extern means i declare a variable, just like you implement a function in a source file and declare the prototype in a header to allow other source file to use it.
If you put a global variable in a source file, and use a header to declare it with the extern keyword, each source file including the header will see the variable.
The linker will do the job to tie everything just as it does with functions
extern as a storage class specifier tells the compiler that the object being declared is not a new object, but has storage elsewhere, i.e., is defined elsewhere. You can try this experiment with your code to see how it works. Leave out the keyword extern in your declaration of int a in main(). Then your printf() will print some garbage value, as it would be a new definition of an int with the same identifier, which would hide the global a declared elsewhere.
You use extern to tell the compiler that the variable is defined elsewhere. Without extern in your program compiler would define another variable a (in addition to this in the global scope) in your main() function that would be printed uninitialized.
I think I hvae a fundamental misunderstanding of namespace and/or static variable. But I have tried this test code (typed by hand, forgive typos)
test.h:
namespace test{
static int testNum=5;
void setNum(int value);
}
main.cpp:
#include <test.h>
int test::setNum(int value){
testNum=value;
}
int main(){
test::setNum(9);
cout<<test::testNum;
}
when I run this I get the value 5, not 9 as I would have expected. It seems almost as if I have two instances of the testNum variable, but that seems to be the exact opposite of what static should be doing. I'm guessing I've made a mistake in assuming that these features were identical to their java equvilants somehow...
I also get an error stating that testNum is declared multuple times if I remove the static from my declaration of testNum, could someone explain why that is the case as well?
Thank you
First, your misunderstanding has nothing to do with namespaces, it's only about static. For the rest of this answer I'm going to refer to simply testNum because the fact it's in a namespace is irrelevant.
I'm also assuming you have another file, probably called test.cpp, which also includes test.h and defines the setNum function.
When a variable or function at namespace-scope (i.e. not a class member or local to a function) is declared static it means the entity's name is internal to that file. Formally it has "internal linkage", meaning it can't be referred to by name or linked to from other files (it can be indirectly referred to through a pointer or by passing it as an argument to another function.) That means if several files define static int testNum then each file has its own internal variable with that name, distinct from the testNum in every other file (in fact one file could have static int testnum and another could have static double testnum and another static char* testNum, they'd all be distinct and internal to each file.) If you put a definition like that in header then every file that includes the header has its own testNum.
So with static on your variable in a header you have a different variable called testNum in every file that includes test.h. That means if you set testNum in one file and call a function in a different file which uses testNum it refers to a different variable, which just happens to have the same name.
Because of this, declaring non-const static variables in headers is almost always wrong.
Without static you would have a definition of the testNum variable in every file that includes test.h, which is not allowed: every entity must be defined once and once only in your program. The way to solve that is to declare the variable in the header, but not define it, which you do by telling the compiler the variable is extern:
extern int testNum; // N.B. no "= 1" here
That tells the compiler there is a variable with "external linkage" called testNum, so when code refers to testNum it will always mean the same variable (not some name with internal linakge that is a different entity in every file.) After declaring an extern variable it is your responsibility to ensure there is exactly one definition provided somewhere in the program, so in exactly one file (i.e. not in a header that gets included in multiple files) you define it:
int testNum = 1;
static at namespace scope is a misnomer, and shouldn't be used. It
means simply that the entity declared static has internal name binding;
in other words, that the same name in other translation units will refer
to a different entity, and in the case of variable definitions, that
there will be a separate instance of the variable in each translation
unit. It has no effect on lifetime. (All variables declared or
defined at namespace scope have static lifetime.)
static at namespace scope is also deprecated. Don't use it.
With regards to declaring a variable in a header: prefix it with
extern, and not static. If a variable is declared extern, and
there is no initialization, the declaration is not a definition. Of
course, in this case, you must provide a definition somewhere (in a
single source file). Something along the lines of:
extern int testNum = 5;
int testNum = 5;
int testNum; // implicitly initialized with 0.
EDIT:
To clarify somewhat: there is some confusion here between lifetime and
name binding:
an object has a lifetime (auto, static or dynamic—or temporary, or exception), and
a name is bound to an entity; if the name is declared to be a variable, the entity is an object.
Do not confuse the keyword static with static lifetime. (Functions
can be static, but functions have no defined lifetime in C++; they're
just there.)
The rules regarding these are not very orthognal. Basically, with
regards to lifetime:
all variables declared at namespace scope have static lifetime, always,
variables declared at local scope have auto lifetime unless they are declared static, and
variables declared at class scope have the lifetime of the class object which contains them, unless they are declared static.
regards to lifetime.
Objects with static lifetime come into being sometime before main, and
live until after you return from main.
With regards to name binding:
variables declared at namespace scope have external name binding,
unless they are declared static, in which case they have internal
name binding (but this use of static is deprecated), or if they are
const, and are not declared extern,
variables declared at class scope have external name binding, even if they are declared static, and
variables declared at block scope have no binding.
Finally, there is the question of whether a declaration is a definition
or not. If it is a definition, memory is allocated and the object is
(or may be) initialized. If it is not a definition, it simply tells the
compiler that there is a definition somewhere else for the entity
(object) declared in the declaration. In general, a variable
declaration is a definition unless it is declared extern and does
not have an initializer.
You might want to make sure your code actually has problems before you post it asking what's wrong ;)
I copy/pasted and fixed your typos, and manually did the include:
#include <iostream>
using namespace std;
namespace test{
static int testNum=5;
void setNum(int value);
}
void test::setNum(int value){
testNum=value;
}
int main(){
test::setNum(9);
cout<<test::testNum;
}
result:
$ ./a.out
9
What you haven't said is what else is in your program. If you have more than just main.cpp, and include your test.h, then each .cpp file will have its own copy of testNum. If you want them to share then you need all but one to mark it as extern.
From ISO Standard Draft: §3.0/9:
n3234 says:
A name used in more than one translation unit can potentially refer to the
same entity in these translationunits depending on the linkage (3.5) of the
name specified in each translation unit.
Can anyone explain this point with an example, please?
What is that statement actually saying? Can any one prove this point in terms of a program?
Sure! What this is saying is that if you have multiple source files (translation units) that both use some name (for example, the name of a variable, class or function), then it's possible that those different files are talking about the same variable, class, or function, assuming that that entity was declared in a way that makes it visible across different files (that is, depending on its linkage).
For example, if I have this file:
A.cpp:
int globalInt;
int main() {
globalInt = 137;
}
And this one here:
B.cpp:
extern int globalInt;
void foo() {
globalInt = 42;
}
Then in both files, the name globalInt refers to the global int variable globalInt defined in A.cpp. That's all that this point is saying.
Note, however, that if I declare globalInt without external linkage, then the two files will be talking about different variables. For example, in this case:
C.cpp:
static int globalInt;
int main() {
globalInt = 137;
}
D.cpp:
static int globalInt;
void foo() {
globalInt = 42;
}
Now the globalInt variable referenced in C.cpp is not the same as the one in D.cpp, even though they have the same name.
Hope this helps!
Ah, standards... let's obfuscate the obvious.
It's saying that, if you use a global variable with the same name in two different source files, they will be the same variable if they are extern or don't specify at all, but if any of them are declared static then those will be completely independent because they're only visible in that source file.
int a; // can be seen in other files; this may be duplicated in multiple source files
static int b; // can only be used in this file
extern int c; // explicitly using a visible variable "c" defined in another file
("Linkage" is the static/extern/default global, or auto which is almost never mentioned since it means "allocated on the stack", which is the default for variables declared inside a function and obviously not meaningful for a declaration outside a function. "Translation unit" is a common way for standards to avoid mentioning "files".)