Namespaces with external linkage

14,238

Solution 1

Any global object, like i, must have exactly one definition somewhere in the program, but it can be declared multiple times.

Using extern without an initializer makes a declaration just a declaration. This is appropriate for your header file, but you must still define i somewhere. As well as making the header declaration extern you also need to add a definition (i.e. a copy of the declaration without extern) to one and only one of your source files.

Edit: Reading your question, you say that you want to pass a variable to a function. From a style and code structure point of view, this isn't usually a good reason for using a shared (global) variable. In the absence of any overriding reasons you should normally define a function which takes a parameter and pass a value (possibly from a local variable) from the calling site to that function via its parameter.

Solution 2

The header file should say:

namespace nn {
    extern int i;
}

This is a "declaration" not a "definition". You then want a definition in one and only one file:

namespace nn {
    int i = 1;
}

Of course, a much better approach is just to not have globals at all.

Solution 3

This has nothing really to do with namespaces, and all to do with the linkage, external or otherwise of the symbol i in your various examples. By default, global variables have extern linkage, while global const symbols have static linkage - this explains why it works when you make i const. To resolve your problem, one way is to declare i with extern linkage in the header file, then define it in only one of the implementation files, as shown below:

header:

extern int i;

a.c:

int i:

main.c:

int main()
{
  i = 1; // or whatever
}

Note that I have removed the namespace for clarity - the end result is the same.

Share:
14,238
Admin
Author by

Admin

Updated on October 30, 2022

Comments

  • Admin
    Admin over 1 year

    The problem I have is basically the same as 'greentype' mentions at http://www.cplusplus.com/forum/beginner/12458/

    I'm sharing variables through namespaces and a problem arises when I try to put my function definitions into a separate file.

    Consider the following example, where I want to pass variable 'i', defined in the main code, to the function a():


    * nn.h: *

    #ifndef _NN_H_
    #define _NN_H_
    
    namespace nn {
    int i;
    }
    #endif
    

    * main.cpp *

    #include <iostream>
    #include "nn.h"
    using namespace std;
    using namespace nn;
    
    void a();
    
    int main()
    {
    i=5;
    a();
    }
    
    void a()
    {
    using namespace std;
    using namespace nn;
    
    i++;
    cout << "i = " << i << endl;
    }
    

    But now if I put the definition of a() into a separate file ...


    * a.cpp *

    #include <iostream>
    #include "nn.h"
    
    void a()
    {
    using namespace std;
    using namespace nn;
    
    i++;
    cout << "i = " << i << endl;
    }
    

    ... then I get 'multiple definition' error when linking (g++ main.cpp a.cpp -o main). If I make 'i' declaration in the header file 'extern' (as suggested in other forums), I get 'undefined reference' error. I can compile when 'i' is declared as const in the header, but that's not what I want.

    Any suggestions greatly appreciated.

  • Admin
    Admin over 14 years
    So the only way to get it to work is to make 'i' global, i.e. put the definition 'namespace nn { int i=5;}' in main.cpp, above int main() (and make the declaration 'extern'). But notice that in the original example (where function a() is in the SAME FILE as main()), 'i' was not global - I defined it within main(), yet still was able to share it with, and modify in, a() through the namespace. That is the framework I need to retain, because I can't really make 'i' global, since it (and other variables I have and need to share) is CALCULATED in main() - I don't know their values in advance.
  • CB Bailey
    CB Bailey over 14 years
    No, you didn't define it in main, you just used it in main. The definition was still in nn.h and it was still a namespace scoped variable (i.e. not a function local). You can still calculate values and assign to namespace scoped variables in a function such as main. It is probably better to have i as a local variable in main and pass it (or a reference to it) to a, though.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 14 years
    @PetrH, to be precise, it wasn't global because it was defined in nn, not because it was defined in main (as has been said, it's merely used there). To make i global, you have to put it outside any user defined namespaces. Put it above namespace nn for example. Currently, i is non-global, but still namespace scoped (not local).