Why I can not "extern" a variable from header file?

This is a discussion on Why I can not "extern" a variable from header file? within the C++ Programming forums, part of the General Programming Boards category; Here is the code:
Code:
//file main.cc
//NOTE: main.cc does NOT include any file
extern int a1;
extern int a2;
...

Because header files are not compiled and do not generate any code. There is no definition of a2 anywhere in your program. (IOW: Just because you have a file called test.h, that doesn't mean that it magically appears when you use test.cpp.)

Because a2, which is "declared" in test.h, is never "discovered" by the compiler. The compiler doesn't know that test.h exists; it only compiles source files. main.cc is referring to an "extern int a2", which never exists. The linker is complaining because you're referring to a variable that, as far as it knows, does not exist.

Note that declaring variables (without extern) in header files is a bad idea for the same reason. If you did this, and included the header file twice, the variable would be defined twice. The linker would complain about a multiple declaration, instead of an unresolved one.

"extern" means you assert that the variable is declared elsewhere. If it isn't, it's not going to work.

"Simplicity does not precede complexity, but follows it." -- Alan Perlis
"Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
"The only real mistake is the one from which we learn nothing." -- John Powell

Thanks. But I don't agree with you about "Don't declare any variable in header files"
You can include the header file, so everything is OK.
In the above example, just let main.cc include "test.h"

Originally Posted by dwks

Because a2, which is "declared" in test.h, is never "discovered" by the compiler. The compiler doesn't know that test.h exists; it only compiles source files. main.cc is referring to an "extern int a2", which never exists. The linker is complaining because you're referring to a variable that, as far as it knows, does not exist.

Note that declaring variables (without extern) in header files is a bad idea for the same reason. If you did this, and included the header file twice, the variable would be defined twice. The linker would complain about a multiple declaration, instead of an unresolved one.

"extern" means you assert that the variable is declared elsewhere. If it isn't, it's not going to work.

That will just lead to a mess. A really, really big mess.
[edit] If you did as you described, you will in effect have created a header file that can only be included in one place. That's not very useful, and it's counter-intuitive. [/edit]

Here's how you can do it. Put the extern declaration in the header file. Put a non-extern declaration in only one source file. Include the header file everywhere you need to use the variable.

This works because this is valid code:

Code:

extern int x;
int x;

It's not a re-declaration or anything. In fact, this is valid code too:

"Simplicity does not precede complexity, but follows it." -- Alan Perlis
"Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
"The only real mistake is the one from which we learn nothing." -- John Powell

I still dont understand why "you will in effect have created a header file that can only be included in one place" ?

Why the code won't work :

Code:

//main.cc
#include "test.h"
...

Code:

//test.cc
#include "test.h"
...

Code:

//test.h
int a;

Originally Posted by dwks

That will just lead to a mess. A really, really big mess.
[edit] If you did as you described, you will in effect have created a header file that can only be included in one place. That's not very useful, and it's counter-intuitive. [/edit]

Here's how you can do it. Put the extern declaration in the header file. Put a non-extern declaration in only one source file. Include the header file everywhere you need to use the variable.

This works because this is valid code:

Code:

extern int x;
int x;

It's not a re-declaration or anything. In fact, this is valid code too:

Because the global variable "x" will end up in TWO source files, and you cannot have two global variables with the same name (unless they are only visible in the source file it's defined).
So in effect, the linker will find two global variables named "x" and give a linking error.
That's why you shouldn't define variables in headers.

dwks hints at because you ARE doing this, you can only include the header from one source file. Try to include from more than one file and you will get a linking error.

Basically, you can only have one definition of a variable (like "int x"). Since header files are by their very nature copied into each source file that includes the header file, putting variable definitions in header files won't work if the header file is included multiple times -- because you will have created multiple variables with the same name.

"extern" says that you're not creating a variable, you're referencing a variable by this name which is created somewhere else.

(I realize I'm repeating what everyone else has just said, but the OP is still online and has been quiet for over 15 minutes, which probably means [s]he's confused. No offence. )

"Simplicity does not precede complexity, but follows it." -- Alan Perlis
"Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
"The only real mistake is the one from which we learn nothing." -- John Powell

Sure. This is sort of going back to your other thread again . . . . A global variable that is declared as "static" is limited in scope to the file in which it is declared. In other words, a static global variable is only visible inside one file. Consequently, each file can have its own set of static global variables, and even call them the same thing as static variables in other files, with no linker errors.

So having a static variable declaration in a header file is just fine. Every source file that includes this header file will get its own copy of the static variable.

"Simplicity does not precede complexity, but follows it." -- Alan Perlis
"Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
"The only real mistake is the one from which we learn nothing." -- John Powell

In C++, you can just define them as constants:
const int VAR = 100;
const int LENGTH = 30;
So long as you do not try to take the address to any of these constants, it will compile.
The reason for this is that the compiler is smart enough to just replace the variables with its value instead or writing code for accessing the variable.
So as long as you don't force its hand - ie force the compiler to create those variables by taking the address of them or something else, it should compile.
Otherwise you would need to use static or define them in one source file and use extern.