I couldn't find any information on this topic neither from stackoverflow or elsewhere.
I know that extern can be used with namespace scope variables in header files to disambiguate a definition int foo; from a bare declaration extern int foo;. That is done to avoid breaking the one-definition-rule, in case multiple files #include this same header file.
In C++17, one can use constexpr inline foo; for globals, which should be better than the old way. One could also use extern inline const/constexpr foo;, both compile without errors, but I have no idea if the extern makes any difference semantically.
So when should one use extern inline with variables, if ever? What is the best practice in C++17?
Based on the wording here:
Inline const variables at namespace scope have external linkage by default (unlike the non-inline non-volatile const-qualified variables)
It seems that there is never any need to add extern to an inline const(expr) variable.
Sometimes a coder prefers to put a declaration first and a definition later. extern is used for this purpose. It can be applied to a declaration of an inline variable as well. But you will not see this in small projects.
extern only means that a declaration is not a definition:
extern int i; //declaration of i
int j; //declare and define j to be equal to zero
inline means that the variable is inline: it can be defined in a different translation unit (TU), as long as the definition is the same, and it must be defined in every TU where it is ODR-used.
inline int k; //declare and define k to be 0, can appear in multiple TUs
extern inline int h; //h is an inline variable but not defined
//it can be used to forward the definition
int f() { return h;}
int h = 10;
There's no sense by using extern with inline. I think it's strange. You'd be giving a definition for a variable that is marked as being defined elsewhere.
You're putting the variable in the translation unit with inline, then asking for the compiler to look for it in another translation unit with extern.
Related
I'm used to writing this sort of code:
//myInclude.h
extern const Type var;
//mySource.cpp
#include "myInclude.h"
const Type var = ...;
...but now that I can write
//myInclude.h
inline const Type var = ... ;
Is there still a use for extern const, or extern generally? Have inline variables rendered that obsolete?
inline does not have rendered extern const obsolete because they are not "orthogonal".
extern and inline when applied to a declaration of a non template const variable (as var), declares that var does not have internal linkage. I suppose this is why one may think that inline make extern not usefull.
But extern and inline also have diverging semantics:
when extern appears in a declaration it implies the declaration is not a definition. It does not implies necessarily that the variable is not inline or that it is defined in an other translation unit.
inline means the declaration is a definition and that this same definition may appear in other translation units.
So an extern const variable declaration may still be usefull when the definition can appear in a specific translation unit. That can be used to increase compilation speed in large projects.
An other use of extern is for forward declaration of const variables. Even forward declaration of constexpr ones:
extern const int var;
// some code that odr-use var
inline constexpr int var = 10;
In the C++11 standard, what is the difference between constexpr and static constexpr global variables when defined in a header? More specifically, when multiple translation units include the same header, which declaration (if any) is guaranteed to define the same variable across the translation units?
e.g.,
cexpr.h:
#ifndef CEXPR_H
#define CEXPR_H
constexpr int cint = 1;
static constexpr int scint = 1;
#endif
a.cpp:
#include "cexpr.h"
b.cpp:
#include "cexpr.h"
In your current example there is no difference: On variable declarations, constexpr implies const, and a const variable at namespace scope has internal linkage by default (so adding static does not change anything).
In C++14, you cannot declare a variable as constexpr and have it have external linkage unless you only ever do this in one single translation unit. The reason is that constexpr variables require an initializer, and a declaration with initializer is a definition, and you must only have a single definition.
However, what you can do is use a normal integral constant, which you can declare (not define) as extern, and in the translation unit where it is defined it can even be used as a constant expression:
lib.h:
extern const int a;
lib.cpp:
#include "lib.h"
const int a = 10;
int b[a] = {1, 2, 3}; // OK in this translation unit
In C++17, there is a new feature "inline variables" which lets you say:
inline constexpr int a = 10;
And this is an "inline definition" that can appear repeatedly, and each definition defines the same entity (just like all the other "inline" entities in the language).
I think this article explains more clear. 6.8 — Global constants and inline variables
Because const globals have internal linkage, each .cpp file gets an independent version of the global variable that the linker can’t see. In most cases, because these are const, the compiler will simply optimize the variables away.
The term “optimizing away” refers to any process where the compiler optimizes the performance of your program by removing things in a way that doesn’t affect the output of your program. For example, lets say you have some const variable x that’s initialized to value 4. Wherever your code references variable x, the compiler can just replace x with 4 (since x is const, we know it won’t ever change to a different value) and avoid having to create and initialize a variable altogether.
So, the "cint " and "scint" are all internal linkage variables.
The best practice to define global variable after C++ 17:
inline constexpr double pi = 0;
Working Mechanism:
C++17 introduced a new concept called inline variables. In C++, the term inline has evolved to mean “multiple definitions are allowed”. Thus, an inline variable is one that is allowed to be defined in multiple files without violating the one definition rule. Inline global variables have external linkage by default.
Inline variables have two primary restrictions that must be obeyed:
1) All definitions of the inline variable must be identical (otherwise, undefined behavior will result).
2) The inline variable definition (not a forward declaration) must be present in any file that uses the variable.
The compiler will consolidate all inline definitions into a single variable definition. This allows us to define variables in a header file and have them treated as if there was only one definition in a .cpp file somewhere. These variables also retain their constexpr-ness in all files in which they are included.
If you can, prefer the static constexpr because with the constexpr it depends on the toolchain how likely it will get done on compile-time. Gcc is most aggressive, MSVS least aggressive and clang is in between.
Instead of leaving some values up to optimizer to decide it will do it at compile-time be more explicit and force it.
Reference:
https://www.youtube.com/watch?v=4pKtPWcl1Go
Let's say I have the following setup in a C++ program, in global/namespace scope (outside of any block):
Situation 1:
a.cpp
extern const int i=5;
b.cpp
extern const int i;
There are two ways, in my mind, that the compiler could see this. One is that the true declaration of i is in b.cpp, while a.cpp has merely a forward declaration and the initialization. (Since we know that for specifically extern consts, initialization at the time of declaration is not required) The other possible executable the compiler could generate would have a.cpp containing the true declaration, with initialization, and the statement in b.cpp is seen as a forward declaration, merely required to be there to assist the compiler in knowing what i is.
How does the compiler decide which file is responsible for the actual declaration, and therefore memory allocation associated with i? This could have outwardly observable effects if, instead of int, a type with an interesting constructor were used.
How does the answer to this question change, if at all, with:
situation 2:
a.cpp
extern const int i;
extern const int i=5;
b.cpp
extern const int i;
Presence of an initializer immediately turns a declaration into a definition (with few exceptions, irrelevant in our context). Which means that
extern const int i = 5;
is a definition of your i. It defines i and gives it external linkage, i.e. creates the actual i and makes it visible to other translation units ("exports" it).
Meanwhile,
extern const int i;
is a non-defining declaration if i. It basically says that i is defined elsewhere ("imports" it).
When you for some reason need a global const object in C++, the proper explicit application of extern becomes crucial, since in C++ const objects have internal linkage by default.
Just keep in mind that in order for a const int object to be eligible for Integral Constant Expressions (ICE), a declaration of that const int object with an ICE initializer has to be visible.
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.
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.