tags:

views:

253

answers:

4

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.

+8  A: 

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.

Charles Bailey
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.
PetrH
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.
Charles Bailey
@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).
Johannes Schaub - litb
+5  A: 

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.

janm
+1  A: 

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.

1800 INFORMATION
A: 

I understand the concepts now. Thank you all for help.

PetrH