Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the 'extern' keyword properly

Tags:

c++

extern

There are sources (books, online materials) that explain the usage of extern as following:

extern int i;        // declaration - has 'extern'
int i = 1;           // definition  - specified by the absence of 'extern'

And there are sources that support the following syntax:

extern int i;        // declaration
extern int i = 1;    // definition  - specified by the equal sign
                     // Both marked with 'extern'

My question is - is this a C vs. C++ distinction, or is it a pre-ANSI vs. ANSI practice?

Now, the more practical question:

Using the second syntax, I want to create a global object (visible from every compilation unit). The constructor takes no parameters, so neither parentheses, nor the equal sign are necessary.

extern MyClass myobject;

Now how can the compiler make the distinction between a declaration and the definition?

EDIT: Back at school, I was used to the first syntax (Borland C). Later I used a compiler (probably some ancient version of GCC) that refused to compile a definition without an 'extern'. That is what made me confused.

like image 681
peter.slizik Avatar asked Aug 08 '12 15:08

peter.slizik


2 Answers

Specifically for your examples, there's no distinction between C and C++ at work here. The basic rule that works in both languages is this: if your declaration includes an initializer, then it is a definition. Period. It does not matter, whether it has explicit extern in it or not. If it has an initializer, then it is a definition.

That means that in namespace scope both extern int i = 1 and int i = 1 are equivalent, i.e. extern in such declaration is redundant. In C++ extern in definitions becomes non-redundant when the declared object is const, since const objects in C++ have internal linkage by default. For example, extern const int c = 42; defines constant c with external linkage.

If a declaration has no initializer, then (and only then) it begins to depend on the presence of extern keyword. With extern it is a non-defining declaration. Without extern it is a definition. (In C it would be a tentative definition, but that's beside the point in our context).

Now, for your practical question. In order to create a global object, you have to declare it as

extern MyClass myobject;

(which will usually be done in a header file), and then define it in some translation unit as

MyClass myobject;

Since your constructor takes no arguments, this is the only way to define your object. (Starting from C++11 you can also use MyClass myobject{}; if you so desire.)

If you had to supply arguments to the constructor (say, 42), you would be able to use both

MyClass myobject(42);

and

extern MyClass myobject(42);

as definition, since presence of an initializer ensures that it is indeed interpreted as a definition.

like image 136
AnT Avatar answered Oct 14 '22 15:10

AnT


For file-scope variables, whether they are of class type or primitive type:

  • extern T t; with no initialiser is a declaration;
  • extern T t = expression; with an initialiser of whatever syntax (assignment, construction, or unified) is a definition;
  • T t; with no initialiser is a definition, initialised to the default value of T;
  • T t = expression; with an initialiser of whatever syntax is a definition.

There is no difference between extern int i = 1; and int i = 1;, and there are arguments to be made for both styles, but in general I'd argue for the second as you should already be aware that a definition at file scope has linkage.

Historically, it appears that pre-ANSI C the extern keyword was not required; see e.g. http://www.jetcafe.org/jim/c-style.html#Declarations

So for a class type, write extern MyClass myobject; for the declaration(s) and MyClass myobject; for the definition.

like image 27
ecatmur Avatar answered Oct 14 '22 14:10

ecatmur