9
...
#include "test1.h"

int main(..)
{
    count << aaa <<endl;
}

aaa is defined in test1.h,and I didn't use extern keyword,but still can reference aaa.

So I doubt is extern really necessary?

httpinterpret
  • 6,409
  • 9
  • 33
  • 37
  • You should provide the contents of test1.h as well. It's possible that you use the wrong terminology for describing what's in test1.h. – sellibitze May 15 '10 at 13:48

5 Answers5

14

extern has its uses. But it mainly involves "global variables" which are frowned upon. The main idea behind extern is to declare things with external linkage. As such it's kind of the opposite of static. But external linkage is in many cases the default linkage so you don't need extern in those cases. Another use of extern is: It can turn definitions into declarations. Examples:

extern int i;  // Declaration of i with external linkage
               // (only tells the compiler about the existence of i)

int i;         // Definition of i with external linkage
               // (actually reserves memory, should not be in a header file)

const int f = 3; // Definition of f with internal linkage (due to const)
                 // (This applies to C++ only, not C. In C f would have
                 // external linkage.) In C++ it's perfectly fine to put
                 // somethibng like this into a header file.

extern const int g; // Declaration of g with external linkage
                    // could be placed into a header file

extern const int g = 3; // Definition of g with external linkage
                        // Not supposed to be in a header file

static int t; // Definition of t with internal linkage.
              // may appear anywhere. Every translation unit that
              // has a line like this has its very own t object.

You see, it's rather complicated. There are two orthogonal concepts: Linkage (external vs internal) and the matter of declaration vs definition. The extern keyword can affect both. With respect to linkage it's the opposite of static. But the meaning of static is also overloaded and -- depending on the context -- does or does not control linkage. The other thing it does is to control the life-time of objects ("static life-time"). But at global scope all variables already have a static life-time and some people thought it would be a good idea to recycle the keyword for controlling linkage (this is me just guessing).

Linkage basically is a property of an object or function declared/defined at "namespace scope". If it has internal linkage, it won't be directly accessible by name from other translation units. If it has external linkage, there shall be only one definition across all translation units (with exceptions, see one-definition-rule).

sellibitze
  • 27,611
  • 3
  • 75
  • 95
  • 1
    So is there any reason to use `extern const int g;`, rather than just `const`? – Casebash Nov 17 '10 at 22:11
  • 1
    @Casebash: If you want to declare a constant in a header but set its value in some cpp file only, you would use extern const. – sellibitze Nov 18 '10 at 12:16
7

I've found the best way to organise your data is to follow two simple rules:

  • Only declare things in header files.
  • Define things in C (or cpp, but I'll just use C here for simplicity) files.

By declare, I mean notify the compiler that things exist, but don't allocate storage for them. This includes typedef, struct, extern and so on.

By define, I generally mean "allocate space for", like int and so on.

If you have a line like:

int aaa;

in a header file, every compilation unit (basically defined as an input stream to the compiler - the C file along with everything it brings in with #include, recursively) will get its own copy. That's going to cause problems if you link two object files together that have the same symbol defined (except under certain limited circumstances like const).

A better way to do this is to define that aaa variable in one of your C files and then put:

extern int aaa;

in your header file.

Note that if your header file is only included in one C file, this isn't a problem. But, in that case, I probably wouldn't even have a header file. Header files are, in my opinion, only for sharing things between compilation units.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Can you elaborate the case you mentioned that "if you link two object files together that have the same symbol defined"? How can `const` fix the problem? – – httpinterpret May 15 '10 at 13:48
  • `extern int aaa;` is not a definition. it's a declaration. Also, `struct foo { int j };` is a definition which is obviously okay in header files. It pays off to use the correct terminology and have read the one definition rule. – sellibitze May 15 '10 at 14:14
  • @sellibitze ,I'm aware of this difference.I'm asking why `const` can fixed the problem mentioned by @paxdiablo – httpinterpret May 15 '10 at 14:19
  • 3
    @httpinterpret constants in C++ have internal linkage i.e, visible to only one cpp file, so you would add definition of constant in header file. – yesraaj May 15 '10 at 14:24
  • Which one of the cpps exactly?Since there may be many cpps that include the header file. – httpinterpret May 15 '10 at 14:27
  • Generally, in the .cpp relative to the .h (or .hpp) in which it's declared, but YMMV, as usual. – Matteo Italia May 15 '10 at 14:34
  • @http, where it goes depends on where it makes sense. If you have a (for example) database source file and aaa is something belonging to that, you would expect `int aaa` in db.cpp and `extern int aaa` in db.h. That's because every compilation unit using the db stuff would include that header and link with the db.o object file made from db.cpp. – paxdiablo May 15 '10 at 14:36
  • @httpinterpret: whichever includes the header file. Each translation unit that does so has its very own internal-linkage constant in this case. – sellibitze May 15 '10 at 15:21
  • If you surround your header file in #ifndef ... you shouldn't have problems with the multiple inclusions/declarations. – Raffi Khatchadourian Nov 14 '11 at 22:53
  • @Raffi, that's not true. Include guards only work at the compilation stage so they will protect a single compilation unit (eg. source file) from multiple inclusions. They will _not_ protect against doubly-defined symbols causing problems at the link stage. Put `int xyzzy;` inside include guards in a header file, include that in _two_ C files then try to link them together - you'll see what I mean. – paxdiablo Nov 14 '11 at 23:53
5

If your test1.h has the definition of aaa and you wanted to include the header file into more than one translation unit you will run into multiple definition error, unless aaa is constant. Better you define the aaa in a cpp file and add extern definition in header file that could be added to other files as header.

Thumb rule for having variable and constant in header file

 extern int a ;//Data declarations
 const float pi = 3.141593 ;//Constant definitions

Since constant have internal linkage in c++ any constant that is defined in a translation unit will not be visible to other translation unit, but it is not the case for variable they have external linkage i.e., they are visible to other translation unit. Putting the definition of a variable in a header, that is shared in other translation unit would lead to multiple definition of a variable, leading to multiple definition error.

yesraaj
  • 46,370
  • 69
  • 194
  • 251
4

In that case, extern is not necessary. Extern is needed when the symbol is declared in another compilation unit.

When you use the #include preprocessing directive, the included file is copied out in place of the directive. In this case you don't need extern because the compiler already know aaa.

Opera
  • 983
  • 1
  • 6
  • 17
  • 2
    @httpinterpret every cpp file along with all the included headers will form a compilation/translation units, cppfile == compilation unit. Header files are just a mechanism to reduce typing, look at your project as a group of cpp files with include"header.h" replaced with actual content of header file. Compilation unit is just object files that see after compilation, linking all those files will give you the exe/dll. – yesraaj May 15 '10 at 13:32
2

If aaa is not defined in another compilation unit you don't need extern, otherwise you do.

Otávio Décio
  • 73,752
  • 17
  • 161
  • 228