Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extern declaration on an extern "C" global variable

Tags:

c++

In C and C++ if I want to use a global variable in other compilation units I will define the variable like:

int g_myVal = 0;

This allocates storage for the int.

In the header file I then declare the variable:

extern int g_myVal;

This informs the compiler that said symbol exists in some other compilation unit. It is then up to the linker to resolve the symbol.

However if I want the variable to be available with "C" linkage I must define the variable (allocate storage) like:

extern "C" int g_myVal = 0;

So how does one then differentiate between allocating storage and just informing the compiler that said symbol exists in another compilation unit?

like image 316
doron Avatar asked Jan 11 '23 12:01

doron


1 Answers

Your confusion stems from the fact that extern and extern "C" do two different things.


About extern

extern on its own is a storage class specifier:

[C++11: 7.1.1/6]: The extern specifier can be applied only to the names of variables and functions. The extern specifier cannot be used in the declaration of class members or function parameters. For the linkage of a name declared with an extern specifier, see 3.5. [ Note: The extern keyword can also be used in explicit-instantiations and linkage-specifications, but it is not a storage-class-specifier in such contexts. —end note ]


About extern "C"

As that trailing note alludes to, there is another context in which you may use the extern keyword and that is as a linkage specifier:

[C++11: 7.5/2]: Linkage (3.5) between C++ and non-C++ code fragments can be achieved using a linkage-specification:

linkage-specification:
    extern string-literal { declaration-seqopt}
    extern string-literal declaration

C++ likes to re-use keywords.


Declarations vs definitions

Now, by default, a variable marked with a linkage specifier is a declaration rather than a definition, so in that sense it is as if you had also used the other meaning of extern:

[C++11: 7.5/7]: A declaration directly contained in a linkage-specification is treated as if it contains the extern specifier (7.1.1) for the purpose of determining the linkage of the declared name and whether it is a definition. Such a declaration shall not specify a storage class. [ Example:

extern "C" double f();
static double f(); // error
extern "C" int i; // declaration
extern "C" {
   int i; // definition
}
extern "C" static void g(); // error

— end example ]

As you can see in the above example, it is still possible to either a declaration or a definition when you use a linkage specifier.

Here's another example of that:

// Everything in this block has C linkage
extern "C" {

   // Declaration of g_myVal
   extern int g_myVal;

   // Definition of g_myVal2
   int g_myVal2;
}

int main()
{
    g_myVal2 = 5;  // ok
    g_myVal  = 6;  // not okay - linker error, symbol not found
}

Live demo


When you add an initialiser...

That all being said, the treatment of g_myVal as a declaration is overruled by your use of an initialiser, which forces the statement to be a definition:

[C++11: 7/8]: Syntactic components beyond those found in the general form of declaration are added to a function declaration to make a function-definition. An object declaration, however, is also a definition unless it contains the extern specifier and has no initializer (3.1). A definition causes the appropriate amount of storage to be reserved and any appropriate initialization (8.5) to be done.

I hope that this clarifies what is going on in your code with these differing meanings of extern.

like image 139
Lightness Races in Orbit Avatar answered Jan 18 '23 13:01

Lightness Races in Orbit