4

I have declared the below namespace in sample.h

// namespace with identifier
namespace N1
{
    int b = 80;
}

sample1.cpp use the above namespace declaration

#include <iostream>
#include "sample.h"

using namespace std;
using namespace N1;

int main(void)
{
    cout << "b (in main) = " << b << endl;
      foo(); //written in sample2.cpp
      return 0;
}

sample2.cpp also use the namespace declared in sample.h

#include <iostream>
#include "sample.h"

using namespace std;
using namespace N1;

void foo(void)
{
    cout << "b = " << b << endl;
}

when I compiled, I got the below errors

$> g++ sample1.cpp sample2.cpp
/tmp/ccB25lEF.o:(.data+0x0): multiple definition of `N1::b'
/tmp/cchLecEj.o:(.data+0x0): first defined here

Let me know how to resolve and how "namespace std" implemented to avoid this problem ?

osdevkid
  • 137
  • 2
  • 3
  • 14

7 Answers7

10

Its not a problem of #ifndef guard.

Use extern in the header file as:

//sample.h
namespace N1
{
    extern int b; //extern is MUST!

    //DONT WRITE : extern int b = 80;
}

Then define it in .cpp file as:

//sample.cpp
namespace N1
{
    int b = 80;  //initialization should be here
}
Nawaz
  • 353,942
  • 115
  • 666
  • 851
6

Include guards will work only during compile time, but the error is at link time. This is because the sample.h is included in both compilation units and a variable N1::b is created in both.
If you really want a variable (not a const) you have to declare it as extern in the header, and create a memory location for it in a separate compilation unit:

// sample.h
#ifndef N1
#define N1
namespace N1 {
    extern int b;
}
#endif

// sample.cpp
#include "sample.h"
namespace N1 {
    int b = 80;
}
king_nak
  • 11,313
  • 33
  • 58
  • This is also not resolved my problem, still I am getting errors like "initialized and declared ‘extern’; redefinition of ‘int N1::b’" – osdevkid May 24 '11 at 11:04
  • @osdevkid: It is solution. You must be doing something else, also. Did you initialize it in the header file itself with `extern` keyword? If you did, that is wrong. – Nawaz May 24 '11 at 11:07
  • @Nawaz : thank you very much, I understood and corrected the problem, now it is working. – osdevkid May 24 '11 at 11:11
  • @osdevkid: I've explained this in my solution! – Nawaz May 24 '11 at 11:13
3

Isn't it just a case of a missing ifdef or pragma once in the sample.h file?

Kristofer
  • 3,201
  • 23
  • 28
3

Every time you #include sample.h into a .cpp module it will create a new linker record for b giving you multiple defines on the link[1].

The int should be defined in sample.cpp, or somewhere else and simply extern int b in sample.h.


[1] some linkers will ignore this and you'll be able to link OK, but most of the time it will generate errors.

Richard Harrison
  • 19,247
  • 4
  • 40
  • 67
2

Your issue is that you have a definition of an object with external linkage in a header file which is included in two separate compilation units. The issue is independent of namespaces as such.

One solution is to make the header file include a declaration only, (e.g. see below) and place the definition on a single source file.

// sample.h
namespace N1
{
    extern int b;
}

// sample.cc
namespace N1
{
    int b = 80;
}

Another solution is to give the object internal linkage, although this will mean that you have multiple objects called b but this may not be an issue. For example, if b is supposed to be constant then this would work because const objects have internal linkage by default.

// sample.h
namespace N1
{
    const int b = 80;
}
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • I have tried out the first method, but it gives errors like "initialized and declared ‘extern’; redefinition of ‘int N1::b’" In Your second method, we cant change the value, I want to change the value of that member in outside – osdevkid May 24 '11 at 11:07
  • @osdevkid: It seems you've written `extern int b = 80;`? – Nawaz May 24 '11 at 11:09
1

If all you want is to define a constant, try this instead:

namespace N1
{
    enum MyEnum
    {
      b = 80
    };
}

Include guards are a good idea for almost any .h file, but they're probably not your problem here. There are two main parts to the all-important One Definition Rule: the first says that each symbol may only be defined once per translation unit (which generally means a .cpp file). That's what include guards are for: they prevent a header from being included twice, which would lead to a symbol (like N::b) being defined more than once in the same translation unit (= .cpp file).

But this is not all, however. Some symbols, such as classes, non-inline functions, and some variable definitions can only be declared once for the entire program. This is not unreasonable: let's suppose you allowed defining an int value called MyInt as 40 in one translation unit and as 80 in another: how the compiler would know which one to use? Of course, you can declare such symbols more than once per program (but only once per translation unit) - or they would only be usable in the translation unit they were declared in. But you cannot define them in more than one translation unit.

Using enum was an easy way to avoid having to separate declaration and definition in your case (since enum isn't subject to the second version of the One Definition Rule), but if you really need a (non-const) global of int type, you could achieve it this way:

sample.h

namespace N1
{
    // The extern keyword tells the compiler that this is is only
    // a declaration and the variable is defined elsewhere.
    extern int b;
}

sample1.cpp

#include "sample.h"

namespace N1
{
    // This is the definition!
    int b = 5;
}

void foo()
{
    using namespace std;
    cout<<N1:b<<endl;
}

sample2.cpp

#include "sample.h"

// No need to define N1::b, since it was already defined in sample1.cpp.

void bar()
{
    using namespace std;
    cout<<N1:b<<endl;
}
Boaz Yaniv
  • 6,334
  • 21
  • 30
  • this is the same way used in "namespace std" ? Anyway it is solved my problem. – osdevkid May 24 '11 at 10:54
  • @Nawaz: this answer *is* correct. I added the extern stuff later, since it takes time to explain everything properly, but the real answer here is "use an enum". You get better encapsulation (no need to write a separate definition and declaration), and the value is practically guaranteed to be optimized as a constant (though consts would probably get optimized by any decent compiler). – Boaz Yaniv May 24 '11 at 11:21
  • Your previous post (`enum MyEnum`) was not an answer. It was alternative. And he might not need enum, as enum values are const. – Nawaz May 24 '11 at 11:24
  • @Nawaz: I known that, and I've explicitly stated it's only useful if he needs a constant. However, looking at his code, it looks like he really does need a constant and not a variable. In this case using an enum is a simpler, safer and possibly better optimized solution. – Boaz Yaniv May 24 '11 at 11:28
0

The program contains two definitions of the variable N1::b while there must be exactly one. The variable must be declared in the header with the extern and defined only in one source file.

Begemoth
  • 1,389
  • 9
  • 14