2

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?

batman
  • 5,022
  • 11
  • 52
  • 82
  • Using `extern` makes it a *declaration*, but not a *definition*. I.e. `extern` says "it exists somewhere, but not here". So you need exactly one place *without* `extern`. – BoBTFish Sep 17 '12 at 08:23
  • What exactly does it mean when people say "a non-const variable is extern by default" ? How does one show that omitting `extern` will still keep it `extern`? Isn't that what default means? – batman Sep 17 '12 at 08:39

3 Answers3

3

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.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • Okay, how if I just put a `int BOT_TIME;` in `constants.h` and nothing in `constants.cpp`. Now, there is just one definition, right? Now the variable is defined like normal variables are defined in the main function. Why doesn't this work? Thank you – batman Sep 17 '12 at 08:37
  • The default linkage is `extern` for non-const symbols and `static` /(internal) for const symbols.So *"Nope. How'd you figure?"* is Incorrect. – Alok Save Sep 17 '12 at 08:38
  • @Als are you saying `BOT_TIME` is `extern` by default? (if that's not what you're saying, your comment is confusing to the op) – Luchian Grigore Sep 17 '12 at 08:40
  • @learner no it's not, because if you include the file in more places, they will all define that symbol. – Luchian Grigore Sep 17 '12 at 08:41
  • @LuchianGrigore, Okay, But are you saying non-const variables are not `extern` by default? I've read that in many places. – batman Sep 17 '12 at 08:43
  • I am saying `BOT_TIME` does have a external linkage by default. – Alok Save Sep 17 '12 at 08:43
  • @learner yes I am. `int x;` and `extern int x;` are not equivalent. – Luchian Grigore Sep 17 '12 at 08:44
  • @Als not the same thing to what the op stated in the question. external linkage != variable declared with extern. Otherwise what'd be the difference? – Luchian Grigore Sep 17 '12 at 08:45
  • @learner when you declare a variable with extern, you specify that it has external linkage, but you only declare it, not define it. If you leave it without the `extern` it still has external linkage, but it's also a definition. – Luchian Grigore Sep 17 '12 at 08:48
  • Your last comment should be in the answer. – Alok Save Sep 17 '12 at 08:52
  • @Als good point, I think that's where the confusion came from - confusing linkage with declaration/definition. – Luchian Grigore Sep 17 '12 at 08:54
  • @LuchianGrigore, I get it. Thank you. just extending, is `static const int BOT_TIME` in `constants.h` a declaration and not a definition ? – batman Sep 17 '12 at 09:04
  • @learner that's a definition, but `static` gives internal linkeage. A copy of the symbol is created for each translation unit that defines the variable, so it's not really a global, but multiple copies. – Luchian Grigore Sep 17 '12 at 09:04
  • @LuchianGrigore, so in this case, it is totally fine to leave the `static out`, since it is by default static linkage and also a definition. – batman Sep 17 '12 at 09:06
  • @learner `static` does something completely different. It creates a different copy for the variable everywhere where you use it. – Luchian Grigore Sep 17 '12 at 09:08
  • @LuchianGrigore, but that is exactly what internal(static) linkage is, isn't it? code in that translation unit will be linked with an internal copy of the variable ,so each translation unit will end up having a copy. – batman Sep 17 '12 at 09:17
  • @learner yes... (I meant it does something completely different than `extern`) – Luchian Grigore Sep 17 '12 at 09:23
2

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?

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • `compiler cannot find its definition and hence complains`. Isn't it the linker that complains here? Now that I've declared it extern, the compiler will leave a place of that variable for the linker to fill. But the linker won't find it. Please correct me if I'm wrong. – batman Sep 17 '12 at 08:45
  • @learner: Yes you are correct.It is the job of the linker to link the definition.I should have said *Implementation* or rather specifically Linker and not compiler. – Alok Save Sep 17 '12 at 08:46
0
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.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165