Namespaces with external linkage
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.
Admin
Updated on October 30, 2022Comments
-
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 over 14 yearsSo 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 over 14 yearsNo, you didn't define it in
main
, you just used it inmain
. The definition was still innn.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 havei
as a local variable inmain
and pass it (or a reference to it) toa
, though. -
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 inmain
(as has been said, it's merely used there). To makei
global, you have to put it outside any user defined namespaces. Put it above namespacenn
for example. Currently,i
is non-global, but still namespace scoped (not local).