extern definition?

Started by
3 comments, last by Adam_42 9 years, 9 months ago

So, until now I thought that extern was used in a declaration, just to say that the variable is actually defined somewhere else. But I tried this:

extern int i = 10; (global var)

to my surprise, the code ran fine. Can someone explain this?

Advertisement
You have it almost right.

The extern keyword specifies that a name has external linkage; that is, that the name should be externally visible between modules. (It has two other uses, but those aren't what you asked about.) For a variable like the one above, marking it as extern also means it has static duration, but since your variable was global, it had that already.

In many ways, "extern" is the opposite of "static". Both mean that the object will be created before program execution, but "extern" means the name is exported by the compiler so that others can link with it, "static" means the name is kept private so it doesn't collide with other similar names.

If you wrote:
extern int i;
Then the variable has external linkage but is not defined here. It serves as a forward declaration to the compiler. The compiler will leave it as a hole to be filled in by the linker. It is much like a function declaration in that respect, it is declared but not defined here.

When you wrote:
extern int i = 0;
Then the variable still has external linkage, and you have defined it in this module. This is similar to a function body, it is an actual definition, the actual thing, rather than just a name that exists somewhere for the linker to fill in later.

may i ask what the other 2 uses of extern are? (probably one is to use the C linkage)

Yes, one use is language linkage. Only two are guaranteed to be supported; you can use extern "C" and extern "C++". The standard allows an implementation to provide other languages, for instance the Windows API might have marked things as extern "PASCAL" for their old convention. When used for language linkage can affect things like name mangling, calling convention, and anything else potentially needed for interoperability.

The third usage was introduced in C++11. Marking a template as extern prevents the compiler from implicitly instantiating a template. Sometimes people forget that a template doesn't actually create code, it creates something akin to an adjustable cookie cutter or giant bag of buttons ready to sew on. Normally the compiler needs to spend some effort generating the contents of a template. This is even more the case with type deduction, where the compiler needs to evaluate the template, try adjusting the values or searching through the big bag in an attempt to find versions of the code that doesn't have substitution failures or that match a concrete type that satisfies a long list of code generation rules, then selecting the best match requiring the fewest implicit transformations and finally generating code that best satisfies the match. Marking a template as extern prevents the compiler from implicitly generating the code and trying out all the variations, the compiler will assume that the functions for the type are the best match and that they have already been generated somewhere else (such as another source code file) and basically treated like regular function declarations rather than template declarations. The end result is much faster compilation of template-heavy code, at the cost of reduced inlining and potentially slower execution.


So that's the three. The original usage that dates back to the C roots for external linkage, the great C/C++ schism usage for external language linkage, and the recently introduced use for externally-existent template instances.

I think declaring something as extern and initializing it on the same line can be confusing to people reading the code, and should be avoided. It's usually equivalent to not specifying "extern". gcc will emit a warning if you do it.

That is "int i;" "int i=0;" and "extern int i=0;" all do the same thing at global scope if there's no previous definition of i - they define i and initialize it to zero. The first version can also lead to confusion as some people may think it's uninitialized like it would be if it was a local variable, so I'd suggest avoiding that too.

"extern int i;" is just a declaration - it tells the compiler that there's a definition elsewhere, and the program will fail to link if that definition isn't there when it needs it.

This topic is closed to new replies.

Advertisement