Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does extern work in namespaces?

I'm running a simple program similar to what I found here. It's meant to reduce code bloat when including constants in multiple files. It does this by using const global variables within a namespace with their respective extern forward declarations.

globals.h

#ifndef GLOBALS_H_
#define GLOBALS_H_

namespace Constants
{
    // forward declarations only
    extern const double pi;
    extern const double avogadro;
    extern const double my_gravity;
}

#endif

globals.cpp

namespace Constants
{
    // actual global variables
    extern const double pi(3.14159);
    extern const double avogadro(6.0221413e23);
    extern const double my_gravity(9.2); // m/s^2 -- gravity is light on this planet
}

source.cpp

#include <iostream>
#include <limits>

#include "globals.h"

int main()
{
    double value_of_pi = Constants::pi;

    std::cout << value_of_pi;

    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.get();

    return 0;
}

I assume that Constants::pi gets the value pi contained in the globals.cpp Constants namespace, and is able to do so because it has access to the namespace itself from the included globals.h. What I don't understand is why the const global definitions/initializations in globals.cpp need the extern keyword? I tried removing the extern keywords in globals.cpp thinking that it wasn't needed, but my program won't run without them. I thought extern was only used for forward declarations? Why are they needed for the const global definitions/initializations? Has it something to do with the namespace they are defined in?

like image 463
Wandering Fool Avatar asked May 28 '15 21:05

Wandering Fool


People also ask

Can a namespace be extern?

You don't need to make the namespace extern, you need to make the variables extern. The fact that they are in a namespace is irrelevant.

How do extern functions work?

the extern keyword is used to extend the visibility of variables/functions. Since functions are visible throughout the program by default, the use of extern is not needed in function declarations or definitions. Its use is implicit. When extern is used with a variable, it's only declared, not defined.

How is extern used?

“extern” keyword is used to extend the visibility of function or variable. By default the functions are visible throughout the program, there is no need to declare or define extern functions. It just increase the redundancy. Variables with “extern” keyword are only declared not defined.

How the extern variables are defined and accessed?

An external variable can be accessed by all the functions in all the modules of a program. It is a global variable. For a function to be able to use the variable, a declaration or the definition of the external variable must lie before the function definition in the source code.


1 Answers

It's meant to reduce code bloat when including constants in multiple files

I would suggest not to focus on this kind of optimizations unless it becomes really necessary, and rather choose the simplest design: define those constants directly in the header file and include that header file from all translation units (".cpp files") that need to access those constants. Since those objects are const, they will have internal linkage and the linker won't be screaming at you due to violations of the One Definition Rule.

I tried removing the extern keywords in globals.cpp thinking that it wasn't needed, but my program won't run without them

That's because namespace-scope const objects with static storage duration (like your pi variable) have internal linkage unless you explicitly define them as extern.

I thought extern was only used for forward declarations?

extern is used to declare a variable that is defined in another translation unit (".cpp file"). If the object is const, the translation unit that defines it needs to explicitly mark it as extern in order for it to have external linkage and be visible from other translation units (this wouldn't be necessary if the object were not const).

Has it something to do with the namespace they are defined in?

No, this is the rule for all namespace-level const objects with static storage duration, and it is specified in paragraph [basic.link]/3 of the C++ Standard:

A name having namespace scope (3.3.6) has internal linkage if it is the name of

(3.1) [...] — a variable, function or function template that is explicitly declared static; or,

(3.2) — a variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or

(3.3) — a data member of an anonymous union.

like image 119
Andy Prowl Avatar answered Oct 16 '22 07:10

Andy Prowl