If I have in header file
namespace Bob
{
extern const T x;
};
And in source file
extern const T Bob::x = 123;
Is the second extern in the source file required or optional?
I've searched and found conflicting information.
From this webpage:
http://msdn.microsoft.com/en-us/library/357syhfh.aspx
But to get the same behavior in C++, you must declare your const variable [in source file] as:
extern const int i = 2;
Usually, the extern keyword tells the compiler not to define a symbol, because it will be defined somewhere else. So writing e.g.
namespace Bob {
extern T x;
}
does not define the variable x, but rather declares it. You can have as many extern declarations as you like. However, if you do not provide a definition the linking will fail. So you have to define
T Bob::x;
somewhere in the code in order to provide the definition.
The const keyword is a little special here, because it implies internal linkage. This means, that the definition of x will not be visible outside the specific compilation unit where it was defined. To alter this behavior you do need to write
extern const T Bob::x = 123;
if you want x to be const and also reference it from other compilation units.
----yet another edit----
Just to be absolutely clear:
If a const variable is supposed to be referenced outside of its compilation unit, then you must explicitly declare it extern.
However, if the declaration is given separately from the definition, then the definition does not necessarily need to specify the keyword extern again. Yet another example for demonstration:
myheader.h
extern const int i;
This declares i a const integer with external linkage, but does not define it.
main.cpp, version 1
#include "myheader.h" //Through the include, the above declaration of `i` comes before its definition.
const int i=123; // Although the `extern` modifier is omitted here,
// it's still in effect because we already declared `i` as `extern`
// Therefore it makes no difference here, whether or not you specify `extern` again.
// The compiler knows this is a definition either way, because of the initialization.
main.cpp, version 2
//#include "myheader.h"
extern const int i=123; // this line is declaration and definition in one, because we did not include
// the declaration from myheader.h. Thus, to tell the compiler that you want
// `i` with external linkage, you MUST specify `extern`. Otherwise you'll get
// internal linkage.
I hope all this now makes sense to you.
You can control the linkage of a symbol with the static and extern keywords. The default linkage is extern for non-const symbols and static (i.e. internal) for const symbols at namespace scope. This is valid for C++ but not for C (where you would have to declare it as static to make it have internal linkage).
So if you have
const int i = 2;
into a .c file and you use it into another unit by declaring
extern const int i;
that's fine in C since that variable has external linkage by default (and with the extern keyword you're instructing the compiler to find it into another unit), but in C++ the same
const int i = 2;
into a .cpp file (firmstanding what I wrote) has internal linkage and it would have to be defined with
extern const int i = 2;
to explicitly have external linkage and be able to be used into another unit with
extern const int i;
Finally when you initialize a global variable you're always defining it in the module where you're doing it, this means that the following is perfectly valid:
#include <iostream>
using namespace std;
#define T int
extern const T x; // This is a declaration
extern const T x = 123; // This is a definition
int main() {
std::cout << x; // 123
return 0;
}
That means the second 'extern' keyword is also unnecessary.
Related
In my project, I have a header file containing the following lines.
extern enum class options {alpha, beta, gamma, theta};
extern options P1, P2;
Compilation gives me
error: a storage class can only be specified for objects and
functions
Why?
How can I rectify this?
Compiler: GCC 9.2.0
extern is applied to variables to specify that they have external linkage. What you have is not a variable but an enum definition, therefore extern cannot be applied to it.
What you can do is apply extern to variables at file scope of the enum type.
For example, your header file would have:
enum options {alpha, beta, gamma, theta};
extern options myoption;
And in one source file you would have:
options myoption;
There's no storage associated with an enum class definition. So it doesn't make sense for it to be marked as extern.
A variable whose type is an enum class, on the other hand, can certainly be extern because there's storage associated with a variable to hold the value of that variable. The location of this storage is something that the linker must ultimately work out.
It makes sense to know of the existence of a variable without being responsible for designating storage for it at link time. This is how you get global variables. For example:
main.cpp
int foo = 5; // declaration and definition together.
other.cpp
extern int foo; // declaration only, (external definition still required elsewhere)
// but you can now use `foo` in this file. e.g.:
int examineFoo() {
return foo;
}
This is also useful if you want to provide a declaration of a global variable in a header file. For example:
main.cpp
#include "foo.h"
int foo = 5;
foo.h
extern int foo;
other.cpp
#include "foo.h"
int examineFoo() {
return foo;
}
It's okay to encounter both the extern declaration and the definition in the same file. e.g.:
extern int foo;
int foo = 5;
To fix your problem
To fix exactly the example you provided, you can remove extern from the enum class definition, where it does not make sense to have it.
enum class options {alpha, beta, gamma, theta};
extern options P1, P2;
Remember that some non-extern definition of those variables P1 and P2 will be required in another module in order for your program to link if you make use of them.
For you, you probably want the class to be defined in a header, along with an extern declaration of any global variables (yuck) you want in your program.
options.h
enum class options {alpha, beta, gamma, theta};
extern options P1, P2;
options.cpp
#include "options.h"
options P1 = options::alpha, P2 = options::beta;
In options.cpp you include options.h to get the definition of the enum class. It also came with an extern definition of the global variables P1 and P2, which wasn't strictly necessary as they are going to be defined in this file anyway, but it's not illegal to do it.
other.cpp
#include "options.h"
options examineOptionP1() {
return P1;
}
other.cpp is aware of the class definition for options and is aware of extern declarations of P1 and P2.
There is one variable called BOT_TIME that varies with the difficulty of my game, and hence isn't const. There are many files that use it. I intend to use it as a global variable.
1) In constants.h I declare it extern int BOT_TIME.
In constants.cpp, I declare it extern int BOT_TIME.
BUILD => undefined references to the variable in all sources(Yes, I've included the header).
2) In constants.h I declare it int BOT_TIME.
In constants.cpp, I declare it int BOT_TIME.
Since non-consts are by default extern , I decided to leave that keyword.
BUILD => Multiple definition of the variable (shows in each source file that has constants.h included)
3) In constants.h I declare it extern int BOT_TIME.
In constants.cpp, I declare it int BOT_TIME.
This works.
Where is the issue?
Initializing the variable to something in constants.cpp makes it work for cases 1 and 3.
What is this happening?
Which is the right approach?
You can declare a variable as many times as you want, you can and have to define it only once.
extern int BOT_TIME;
is a declaration.
int BOT_TIME;
is a definition.
The definition has to appear in a single implementation file.
Since non-consts are by default extern , I decided to leave that keyword.
Nope. How'd you figure?
To answer the questions:
1) There's no definition, only declarations.
2) The assumption is wrong. You define the symbol multiple times.
3) It works because that's the correct way to do it.
From the comments:
When you declare a variable with extern, you specify that it has external linkage, yes, but you only declare, and not define it. If you leave it without the extern keyword, it still has external linkage, but it's also a definition.
You need to declare the variable in a header file and define it once and only once in a source file.
The correct way to do this is:
constants.h
//declare the symbol as extern
extern int BOT_TIME;
constants.cpp
#include "constants.h"
//define the symbol once and only once
int BOT_TIME;
XXXX.cpp
#include "constants.h"
//Include the header file which declares it extern in any source file
//you want to access it
//use BOT_TIME
You can declare a variable as many times but you can only define it once.
If you define a variable more than once you violate the One Definition Rule.
extern int BOT_TIME;
is a declaration and #1 only makes the same declaration twice, this is allowed but it doesn't work since you never define the variable.Note that every extern variable must be defined once or the compiler cannot find its definition and hence complains.
In #2 you define the same symbol multiple times in different translation units.This violates the One Definition rule and hence the linker reports the same.
#3 is the correct way to do it.
Good Read:
What is the difference between a definition and a declaration?
extern int x; // declaration
int x; // definition
extern int x = 3; // definition
In general, you need a declaration in the header file, for source files that need to know about x. You need one definition, in one source file, so that there is actually an object x.
I know one should not use global variables but I have a need for them. I have read that any variable declared outside a function is a global variable. I have done so, but in another *.cpp file, that variable could not be found. So it was not really global. Isn't it so that one has to create a header file GlobalVariabels.h and include that file to any other *cpp file that uses it?
I have read that any variable declared outside a function is a global variable. I have done so, but in another *.cpp File that variable could not be found. So it was not realy global.
According to the concept of scope, your variable is global. However, what you've read/understood is overly-simplified.
Possibility 1
Perhaps you forgot to declare the variable in the other translation unit (TU). Here's an example:
a.cpp
int x = 5; // declaration and definition of my global variable
b.cpp
// I want to use `x` here, too.
// But I need b.cpp to know that it exists, first:
extern int x; // declaration (not definition)
void foo() {
cout << x; // OK
}
Typically you'd place extern int x; in a header file that gets included into b.cpp, and also into any other TU that ends up needing to use x.
Possibility 2
Additionally, it's possible that the variable has internal linkage, meaning that it's not exposed across translation units. This will be the case by default if the variable is marked const ([C++11: 3.5/3]):
a.cpp
const int x = 5; // file-`static` by default, because `const`
b.cpp
extern const int x; // says there's a `x` that we can use somewhere...
void foo() {
cout << x; // ... but actually there isn't. So, linker error.
}
You could fix this by applying extern to the definition, too:
a.cpp
extern const int x = 5;
This whole malarky is roughly equivalent to the mess you go through making functions visible/usable across TU boundaries, but with some differences in how you go about it.
You declare the variable as extern in a common header:
//globals.h
extern int x;
And define it in an implementation file.
//globals.cpp
int x = 1337;
You can then include the header everywhere you need access to it.
I suggest you also wrap the variable inside a namespace.
In addition to other answers here, if the value is an integral constant, a public enum in a class or struct will work. A variable - constant or otherwise - at the root of a namespace is another option, or a static public member of a class or struct is a third option.
MyClass::eSomeConst (enum)
MyNamespace::nSomeValue
MyStruct::nSomeValue (static)
Declare extern int x; in file.h.
And define int x; only in one cpp file.cpp.
Not sure if this is correct in any sense but this seems to work for me.
someHeader.h
inline int someVar;
I don't have linking/multiple definition issues and it "just works"... ;- )
It's quite handy for "quick" tests... Try to avoid global vars tho, because every says so... ;- )
In C++, const variables are implicitly hidden from other translation units. Is is possible to prevent that?
Yes, prefix the definition with extern eg.
extern const int x = 10;
Use the extern keyword:
extern const int x = 10;
This forces the variable to have external linkage.
For namespace-scope variables this is usually the default, and you'd use static (or, better, an anonymous namespace) to force internal linkage.
I didn't actually know that namespace-scope const variables have internal linkage by default until I read your question and tried it out, so thanks for that. Learn something new every day!
It can be achieved by means of the extern keyword:
// a.cpp
extern const int x = 10; // definition
// b.cpp
extern const int x; // declaration
The effect this will have is that you will not need to recompile b if the value of the constant changes in a, but at the same time you loose the ability to use x as a compile time constant inside b.cpp (i.e. you will not be able to write int array[x];).
If there isn't a very strong reason for this, I would rather have the constant defined in a header file and included in all translation units that require it;
// c.h
const int x = 10;
// a.cpp
#include "c.h"
// b.cpp
#include "c.h"
You will have to recompile all translation units that depend on the constant with each change, but you will be able to use it at compile time in all translation units. The limitation of this approach is that if you change the constant and only recompile some of the translation units, the value of the constant will be inconsistent (this is a violation of the ODR).
This is from the <iostream>:
namespace std
{
extern istream cin; ///< Linked to standard input
extern ostream cout;
...
It seems by using extern the data types defined in other namespaces will just be available?
extern means "these variables are defined in some other compilation unit (.cpp or .lib file)"
In this case, you #include <iostream> into your .cpp file, and because cin and cout are declared as extern, the compiler will let you use them without complaining. Then, when the linker runs, it looks up all of the extern variables and sorts it all out.
extern is used to refer to a variable defined in a different compilation unit (for now, you can think of a compilation unit as a .cpp file). The statements in your example declare rather than define cin and cout. It is telling the compiler that the definition of these objects is found in another compilation unit (where they are not declared as extern).
No, this is an explicit way to say cin and cout are declared without actually defining them.
The extern keyword tells the compiler that a variable is declared in another source(i.e outside the current scope). The linker then finds this actual declaration and sets up the extern variable to point to the correct location.
variables declared by extern statements will not have any space allocated for them, as they should be properly defined elsewhere. If a variable is declared extern, and the linker finds no actual declaration of it, it will show error.
Eg. extern int i;
//this declares that there is a variable named i of type int, defined somewhere in the program.
Some answers say here that extern means that variable is defined in other compilation unit. Then, following should not compile as no other compilation unit or file is provided to compiler.
extern int a;
int main(){
std::cout<<a<<std::endl; //Prints 3
}
int a=3;
So, I think extern is explicitly used to separate the declaration and definition in case of variable as stated in one of answer. I think it is useless in case of functions.