In C and C++ if I want to use a global variable in other compilation units I will define the variable like:
int g_myVal = 0;
This allocates storage for the int.
In the header file I then declare the variable:
extern int g_myVal;
This informs the compiler that said symbol exists in some other compilation unit. It is then up to the linker to resolve the symbol.
However if I want the variable to be available with "C" linkage I must define the variable (allocate storage) like:
extern "C" int g_myVal = 0;
So how does one then differentiate between allocating storage and just informing the compiler that said symbol exists in another compilation unit?
Your confusion stems from the fact that extern and extern "C" do two different things.
About extern
extern on its own is a storage class specifier:
[C++11: 7.1.1/6]: The extern specifier can be applied only to the names of variables and functions. The extern specifier cannot be used in the declaration of class members or function parameters. For the linkage of a name declared with an extern specifier, see 3.5. [ Note: The extern keyword can also be used in explicit-instantiations and linkage-specifications, but it is not a storage-class-specifier in such contexts. —end note ]
About extern "C"
As that trailing note alludes to, there is another context in which you may use the extern keyword and that is as a linkage specifier:
[C++11: 7.5/2]: Linkage (3.5) between C++ and non-C++ code fragments can be achieved using a linkage-specification:
linkage-specification:
extern string-literal { declaration-seqopt }
extern string-literal declaration
C++ likes to re-use keywords.
Declarations vs definitions
Now, by default, a variable marked with a linkage specifier is a declaration rather than a definition, so in that sense it is as if you had also used the other meaning of extern:
[C++11: 7.5/7]: A declaration directly contained in a linkage-specification is treated as if it contains the extern specifier (7.1.1) for the purpose of determining the linkage of the declared name and whether it is a definition. Such a declaration shall not specify a storage class. [ Example:
extern "C" double f();
static double f(); // error
extern "C" int i; // declaration
extern "C" {
int i; // definition
}
extern "C" static void g(); // error
— end example ]
As you can see in the above example, it is still possible to either a declaration or a definition when you use a linkage specifier.
Here's another example of that:
// Everything in this block has C linkage
extern "C" {
// Declaration of g_myVal
extern int g_myVal;
// Definition of g_myVal2
int g_myVal2;
}
int main()
{
g_myVal2 = 5; // ok
g_myVal = 6; // not okay - linker error, symbol not found
}
Live demo
When you add an initialiser...
That all being said, the treatment of g_myVal as a declaration is overruled by your use of an initialiser, which forces the statement to be a definition:
[C++11: 7/8]: Syntactic components beyond those found in the general form of declaration are added to a function declaration to make a function-definition. An object declaration, however, is also a definition unless it contains the extern specifier and has no initializer (3.1). A definition causes the appropriate amount of storage to be reserved and any appropriate initialization (8.5) to be done.
I hope that this clarifies what is going on in your code with these differing meanings of extern.
In this case, putting the initializer = 0 changed the declaration to a definition, which is why storage is allocated here. (The same would have happened even with just plain extern.)
Related
According to C++ Primer, we can provide an initializer on a variable defined as extern, but doing so overrides the extern. An extern that has an initializer is a definition:
extern double pi = 3.1416; // definition
It is also stated in the book that providing an initializer on an extern inside a function is an error. These two statements together are a little confusing in my opinion and they give rise to the following questions in my mind:
If providing an initializer on an extern outside any function can override the extern, why can providing it on an extern inside a function not?
I also don't understand why someone would want to both obtain a declaration adding the extern keyword and provide an initializer. Is it not the same as defining a variable and providing an initializer on it? If it is not, why? Is the answer the reason why we cannot provide an initializer on an extern inside a function?
According to C++ Primer, we can provide an initializer on a variable defined as extern, but doing so overrides the extern.
Only partially.
Providing an initializer forces the declaration to be a definition (except in the case of some static members of classes). It thus partially counteracts the effect of extern, which usually suppresses definition. However, extern can have other effects, and the initializer doesn't nullify those.
It is also stated in the book that providing an initializer on an extern inside a function is an error.
Yes. At block scope, extern is used to force a declaration to have external or internal linkage (rather than declaring a local variable). However, the language prohibits defining such a variable in a local scope. You can only declare it there, and provide a matching definition at namespace scope. If you provide an initializer, then you're trying to define the variable there, which is not allowed.
If providing an initializer on an extern outside any function can override the extern, why can providing it on an extern inside a function not?
As I explained, this premise is false. The initializer, in both cases, makes the declaration into a definition. In both cases, it does not override the fact that extern affects the linkage of the entity being declared.
I also don't understand why someone would want to both obtain a declaration adding the extern keyword and provide an initializer. Is it not the same as defining a variable and providing an initializer on it? If it is not, why?
When we use extern together with an initializer, it is usually because we are trying to define a const object with external linkage. See below:
// At global scope:
const int c1 = 42; // definition with internal linkage
extern const int c2; // declaration with external linkage
extern const int c3 = 42; // definition with external linkage
I am very very sorry. I didn't know my incomplete code attachment would create such a mess. I am very glad to see so many sincere helps.
This code will compile:
int myadd(int, int);
static int main_stat = 5;
int main()
{
int i, j;
main_stat = 13;
j = myadd(-1,7);
i = main_stat;
cout << j << i; // 3 and 13
return 0;
}
myadd.cpp
extern int main_stat = -3;
int myadd(int x,int y)
{
int t = main_stat;
t = x + y;
y = t +main_stat;
return y; // will return 3
}
See I defined and extern linking main_stat. Why is that legal? I thought you could only link and not define.
Is storage allocated in the stack frame of myadd function call? Global static are allocated on heap, I believe, right?
EDIT
I am sorry, but I think this time I will narrow down my questions:
From C++ Primer 4ed
An extern declaration may include an initializer (when combined
becomes definition) only if it appears outside a function.
I am clear about one-definition rule.
Q1. Which copy of main_stat does myadd(int,int) uses when it is called? The same copy as the main has, but with a different value (which I can test) ? Or does each function has its own static global copy?
Q2. Is memory allocated on the heap for these global static variables? I know many things are up to implementation, but isn't heap used for static variables?
Q3. I know the followings two are valid
extern int x; // means int x is defined elsewhere
extern int x = 3; // declared and defined
Why do we want the second one if we can just declare a static global variable within the namespace of myadd ? How does it make things clear like aschepler said?
All variable declarations with an initializer are also definitions;
that's an overriding rule. Regardless of extern. There are even
cases where you need an extern on a definition: you can only
instantiate a template using a variable which has external linkage. And
const variables have internal linkage by default, so you need
something like:
extern int const i = 42;
if you want to use it to instantiate a template<int const*>.
The following is a declaration and definition:
int x;
Adding extern says "make it a declaration only, please".
But when you are providing a value, the line has to be a definition, so the variable gets extern storage class and you just happen to be defining it right in place anyway:
extern int x = 3;
The linkage semantics are as they usually are for extern, and the storage location is just as it would be for a normal definition int x = 3 — i.e. in that TU at namespace scope. myadd is not relevant at all.
It's a hard one to "prove", because it's a case of "there's no rule against it".
Here's the best quote:
[n3290: 3.1/2]: A declaration is a definition unless it declares
a function without specifying the function’s body (8.4), it
contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a
function-body, [..]
And some other pertinent information:
[n3290: 3.5/2]: A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:
When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.
[n3290: 3.5/12]:The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration
have linkage. 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 there is more than one such matching entity,
the program is ill-formed. Otherwise, if no matching entity is found,
the block scope entity receives external linkage. [..]
extern int main_stat=-3;
declares and defines main_stat, While:
extern int main_stat;
just declares the variable main_stat.
You can have as many declarations as you want but you can have only one Definition.
The keyword extern, indicates External Linkage. Without it main_stat would be static and have Internal linkage and you cannot not use main_stat from another translation unit.
Is storage allocated in the stack frame of myadd ?
No definitely not on the stackframe of add.
Where the memory is allocated is implementation defined but you have the assurance that the object will be alive throughout the duration of the program.
The question apparently stems from some misconception.
Some people believe that extern keyword always turns a definition into a non-defining declaration. This is simply not true.
The keyword extern simply gives the declared entity external linkage. It can be applied to declarations. It can be applied to definitions (and remember that definitions are declarations as well).
So, saying that one can't define an extern entity is absolutely incorrect. One can. There's no problem with that at all.
The confusion is usually caused by the fact that when you apply extern to a definition like
int x; // no initializer
that definition suddenly turns into a non-defining declaration. This is true, but this is is no more than a one-off quirk of extern keyword that has to be remembered. If you take a definition like
int x = 42;
then applying the extern keyword to it will still preserve it as a definition, i.e. no quirks in this case.
First, according to your comment, the file containing the main function has the definition static int main_stat = 10;. You should be aware that this is not the same variable as you defined in the file containing myadd because as static variable its scope is restricted to that file. Indeed, thanks to that static variable with the same name, main is not able to access the variable you defined in this file.
But that doesn't mean that either variable was created on the stack. Both are separate global variables, it's just that the variable main_stat in the file containing main (I'll call that file main file for short, and this one myadd file) is not available in any other file, while the variable main_stat you defined here can be accessed from any file which contains the declaration extern main_stat; (note: without initializer!). The main file cannot contain this declaration, however, because it would conflict with the static variable of the same name.
Note that giving an initializer makes your declaration of the variable a definition, that is, it's the same as if you had omitted the extern (note however that if a variable is declared constant, the extern may not be omitted because constants are by default static). The only global extern declarations which are not also definitions are those with extern, but without initializer.
Everyone else has covered this pretty well, but just to show the variants in one place:
int x; // #1
is a declaration and definition. The initial value of x is zero.
int x = 3; // #2
is a declaration and definition.
const int cx; // #3
is illegal in C++.
const int cx = 3; // #4
is a declaration and definition, but cx has internal linkage if this is its first declaration in the translation unit.
extern int x; // #5
is a declaration but NOT a definition. There must be a definition of x somewhere else in the program.
extern int x = 3; // #6
is a declaration and a definition. The extern is unnecessary, but makes things clear.
extern const int cx; // #7
is a declaration but NOT a definition. There must be a definition of cx somewhere else in the program.
extern const int cx = 3; // #8
is a declaration and a definition. The extern is needed unless the previous declaration above was already seen.
Page 60 of C++ Primer 5th edition talks about sharing const variables across files like so
//file_1.cc
extern const int bufSize = fcn();
//file_1.h
extern const int bufSize;
When would bufSize be defined and what is the purpose of extern on file_1.cc? I understand that file_1.cc would define it, but Page 45 of the same book says that providing an initializer for a variable overrides the extern, so why is it necessary to have extern on the const's definition?
According to the standard,
A name having namespace scope (3.3.6) has internal linkage if it is the name of ... a non-volatile variable that is explicitly declared const or constexpr and neither explicitly declared
extern nor previously declared to have external linkage
So there is a special rule that variables at namespace scope have internal linkage when const or constexpr even if they would otherwise have external linkage. I'm not entirely sure why this rule exists but I suspect it's to allow the compiler to inline const variables and hence not allocate any storage for them at all. The extern specifier explicitly overrides this and makes the variable have external linkage again.
providing an initializer for a variable overrides the extern
Now this is a bit different. By default a declaration of a variable is also a definition, but extern suppresses this so you can declare a variable without defining it (i.e. because its definition is in another translation unit). But if you have an initializer then it overrides the extern and the declaration once again becomes a definition. This isn't really related to the rules about internal and external linkage above.
I'm trying to declare a function pointer type (not a variable) that would specify C calling convention. Both
extern "C" typedef void (*PFunc)();
and
typedef extern "C" void (*PFunc)();
produce a syntax error, when used on function level.
extern "C" { typedef void (*PFunc)(); }
extern "C" typedef void (*PFunc)();
both work when used on the global scope; I'd rather keep it local.
What's the proper way, please? I don't want to use compiler specific extentions.
According to this, matching calling conventions between the pointer and the target is the safe thing to do when calling inderectly functions that are declared as extern "C", because C and C++ calling conventions might mismatch. In real life they mostly don't, but still, correctness.
Contrary to what some commenters have said here, calling convention/linkage is part of a function type. It has to be, otherwise this information would not be known when calling the function through the function pointer:
[C++11: 7.5/1]: All function types, function names with external linkage, and variable names with external linkage have a language linkage. [..]
The correct declaration is:
extern "C" typedef void (*PFunc)();
However, at block-scope, you cannot declare a function to have any linkage:
[C++11: 7.5/4]: Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope (3.3). In a linkage-specification, the specified language linkage applies to the function types of all function declarators, function names with external linkage, and variable names with external linkage declared within the linkage-specification. [..]
So, you will have to stick with a namespace-scope declaration. If you still want to restrict the visibility of the declaration, you could "shelter" it from other code in the same translation unit, using an unnamed namespace.
Yes, linkage specification (extern "C") should be in namespace scope (or global) by Standard.
extern "C" typedef void (*pf)();
is right. If your compiler doesn't accept it, it is a bug of the compiler.
Guessing, but it might be because you are declaring the function as (), in C that means it can take both an INT and VOID... Try explicitly saying (void)
I am very very sorry. I didn't know my incomplete code attachment would create such a mess. I am very glad to see so many sincere helps.
This code will compile:
int myadd(int, int);
static int main_stat = 5;
int main()
{
int i, j;
main_stat = 13;
j = myadd(-1,7);
i = main_stat;
cout << j << i; // 3 and 13
return 0;
}
myadd.cpp
extern int main_stat = -3;
int myadd(int x,int y)
{
int t = main_stat;
t = x + y;
y = t +main_stat;
return y; // will return 3
}
See I defined and extern linking main_stat. Why is that legal? I thought you could only link and not define.
Is storage allocated in the stack frame of myadd function call? Global static are allocated on heap, I believe, right?
EDIT
I am sorry, but I think this time I will narrow down my questions:
From C++ Primer 4ed
An extern declaration may include an initializer (when combined
becomes definition) only if it appears outside a function.
I am clear about one-definition rule.
Q1. Which copy of main_stat does myadd(int,int) uses when it is called? The same copy as the main has, but with a different value (which I can test) ? Or does each function has its own static global copy?
Q2. Is memory allocated on the heap for these global static variables? I know many things are up to implementation, but isn't heap used for static variables?
Q3. I know the followings two are valid
extern int x; // means int x is defined elsewhere
extern int x = 3; // declared and defined
Why do we want the second one if we can just declare a static global variable within the namespace of myadd ? How does it make things clear like aschepler said?
All variable declarations with an initializer are also definitions;
that's an overriding rule. Regardless of extern. There are even
cases where you need an extern on a definition: you can only
instantiate a template using a variable which has external linkage. And
const variables have internal linkage by default, so you need
something like:
extern int const i = 42;
if you want to use it to instantiate a template<int const*>.
The following is a declaration and definition:
int x;
Adding extern says "make it a declaration only, please".
But when you are providing a value, the line has to be a definition, so the variable gets extern storage class and you just happen to be defining it right in place anyway:
extern int x = 3;
The linkage semantics are as they usually are for extern, and the storage location is just as it would be for a normal definition int x = 3 — i.e. in that TU at namespace scope. myadd is not relevant at all.
It's a hard one to "prove", because it's a case of "there's no rule against it".
Here's the best quote:
[n3290: 3.1/2]: A declaration is a definition unless it declares
a function without specifying the function’s body (8.4), it
contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a
function-body, [..]
And some other pertinent information:
[n3290: 3.5/2]: A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:
When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.
[n3290: 3.5/12]:The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration
have linkage. 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 there is more than one such matching entity,
the program is ill-formed. Otherwise, if no matching entity is found,
the block scope entity receives external linkage. [..]
extern int main_stat=-3;
declares and defines main_stat, While:
extern int main_stat;
just declares the variable main_stat.
You can have as many declarations as you want but you can have only one Definition.
The keyword extern, indicates External Linkage. Without it main_stat would be static and have Internal linkage and you cannot not use main_stat from another translation unit.
Is storage allocated in the stack frame of myadd ?
No definitely not on the stackframe of add.
Where the memory is allocated is implementation defined but you have the assurance that the object will be alive throughout the duration of the program.
The question apparently stems from some misconception.
Some people believe that extern keyword always turns a definition into a non-defining declaration. This is simply not true.
The keyword extern simply gives the declared entity external linkage. It can be applied to declarations. It can be applied to definitions (and remember that definitions are declarations as well).
So, saying that one can't define an extern entity is absolutely incorrect. One can. There's no problem with that at all.
The confusion is usually caused by the fact that when you apply extern to a definition like
int x; // no initializer
that definition suddenly turns into a non-defining declaration. This is true, but this is is no more than a one-off quirk of extern keyword that has to be remembered. If you take a definition like
int x = 42;
then applying the extern keyword to it will still preserve it as a definition, i.e. no quirks in this case.
First, according to your comment, the file containing the main function has the definition static int main_stat = 10;. You should be aware that this is not the same variable as you defined in the file containing myadd because as static variable its scope is restricted to that file. Indeed, thanks to that static variable with the same name, main is not able to access the variable you defined in this file.
But that doesn't mean that either variable was created on the stack. Both are separate global variables, it's just that the variable main_stat in the file containing main (I'll call that file main file for short, and this one myadd file) is not available in any other file, while the variable main_stat you defined here can be accessed from any file which contains the declaration extern main_stat; (note: without initializer!). The main file cannot contain this declaration, however, because it would conflict with the static variable of the same name.
Note that giving an initializer makes your declaration of the variable a definition, that is, it's the same as if you had omitted the extern (note however that if a variable is declared constant, the extern may not be omitted because constants are by default static). The only global extern declarations which are not also definitions are those with extern, but without initializer.
Everyone else has covered this pretty well, but just to show the variants in one place:
int x; // #1
is a declaration and definition. The initial value of x is zero.
int x = 3; // #2
is a declaration and definition.
const int cx; // #3
is illegal in C++.
const int cx = 3; // #4
is a declaration and definition, but cx has internal linkage if this is its first declaration in the translation unit.
extern int x; // #5
is a declaration but NOT a definition. There must be a definition of x somewhere else in the program.
extern int x = 3; // #6
is a declaration and a definition. The extern is unnecessary, but makes things clear.
extern const int cx; // #7
is a declaration but NOT a definition. There must be a definition of cx somewhere else in the program.
extern const int cx = 3; // #8
is a declaration and a definition. The extern is needed unless the previous declaration above was already seen.