2

I have 4 files:

  • shared.h
  • main.cpp
  • something.h
  • something.cpp

shared.h:

#ifndef SHARED_H
#define SHARED_H

int* sth;

#endif

something.h:

#ifndef SOMETHING_H
#define SOMETHING_H

class foo
{
   public:
      void printVar();
};

#endif

something.cpp:

#include <iostream>
#include "something.h"
#include "shared.h"

using namespace std;

void foo::printVar()
{
    cout<<"Foo: "<<*sth<<endl;
};

main.cpp:

#include <cstdlib>
#include <iostream>
#include "shared.h"
#include "something.h"

using namespace std;

int main(int argc, char *argv[])
{
    sth=new int(32);

    foo x;
    cout<<"Main: "<<*sth<<endl;
    x.printVar();

    system("PAUSE");
    return EXIT_SUCCESS;
}

Compiler returns multipe definition of *sth;

I added static modifier to the *sth and it compiles, but crashes. I changed the printings to print the adresses of pointer and I had program returned:

Main: 0x3e0f20
Foo: 0

Why is the foo's pointer not assigned? I want to assign it only once in main and then share in other files... How can I do this? Is it something with extern modifier?

Thanx for any replies.

noisy cat
  • 2,865
  • 5
  • 33
  • 51

5 Answers5

5

In shared.h you want to say:

extern int* sth;

to promise the compiler that sth exists somewhere.

Then in one (and only one) of the .cpp files you need to write:

int* sth;

To make it actually exists. In general you probably want to read about the difference between declaration and definition. As a rule of thumb you only want to declare things in header files, not define them.

When you wrote static previously you said that a variable with the same name exists in every file, but is "local" to each, i.e. the sth in main.cpp won't be the same as the sth in something.cpp.

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • and in other files I should use extern too or not? – noisy cat Mar 29 '12 at 16:30
  • @kittyPL in other files `#include` with the header file is sufficient. The `extern` is a promise to the compiler that it will exist somewhere when it needs it to. The `int* sth` without `extern` makes it actually exist in that specific place. You can write `extern int* sth` as many times as you like, but it's safer to only write it once in a single header file. – Flexo Mar 29 '12 at 16:32
  • [Linker error] undefined reference to `sth' ... what now? It happens in the file without int *sth; Same with extern int* sth. – noisy cat Mar 29 '12 at 16:33
  • @kittyPL in which case you've not linked it against the file that does have `sth`, or simply forgotten to put the `int* sth;` in one and only one .cpp file - make sure they're both getting compiled into the same project properly. (Either that or it's a typo somewhere) – Flexo Mar 29 '12 at 16:35
  • Worked when I put int* sth; in something.h... Is that becouse Its included before main? – noisy cat Mar 29 '12 at 16:37
4

Yes, use extern. Put extern int* sth; in the header, and then in one of the source files put int* sth;.

extern tells the compiler and linker that the actual variable/function definition is in another compilation unit (i.e. another source file).

Cornstalks
  • 37,137
  • 18
  • 79
  • 144
2

You need to mark sth as extern in the header to make it a declaration, and provide a definition for it in one of the cpp files. Otherwise, the variable is declared in each compilation unit where the header is included, which is not the effect you are looking for.

P.S. I assume that you know why global variables are not good, right?

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

"I have 4 files".

Let me stop you right there. I agree that you have four files, but that's not really relevant. You have two translation units. A translation unit is the quantum of text that is fed into your compiler. Your translation units, let's call them MAIN and SOMETHING, consist of the result of preprocessing your files main.cpp and something.cpp, respectively.

After preprocessing, each of your translation units includes a line int *sth; This line declares and defines the variable sth.

The one-definition-rule requires that you have, in your entire program, exactly one (not more, not fewer) definition of sth. In order to accomplish this, you must have exactly one source-code line int *sth; in exactly one translation unit, and as many extern int *sth; as you require.

In your case, I would put int *sth; in MAIN and extern int *sth; in SOMETHING. Additionally, you can have as many extra copies of extern int *sth; as you feel like -- they won't hurt anything.

Now, back to your four files. You should put extern int *sth; in shared.h. This means that MAIN and SOMETHING will both have an extern line in them. You should also put int *sth; in main.cpp, so that MAIN will have the definition.

And there you are: MAIN and SOMETHING both have extern lines, so they are both referring to the same variable. MAIN also has a definition. so the sth variable has exactly one of those.


Aside: Why does static int *sth; in shared.h do the wrong thing?

Because each of the two translation units see their own static declaration. A static declaration reduces the linkage of the declared name to that single translation unit.

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
1

You don't want to make it a static global as that will create a local sth in every translation unit and you are only allocating it in one. This is why it crashed in Foo::printVar as in that scope it was an uninitialized pointer.

You want to declare it as extern int* sth; in the shared header then put int* sth; before main or in at least one place before it's used.

Actually, if you really need a globally accessible object, allocated on the heap, and you want to share it then it may be better as extern std::shared_ptr<int> sth;. Define it as std::shared_ptr<int> sth; the same way in one of the CPP files and call std::make_shared to allocate it. This way deallocating the memory will be handled automatically when the last object that uses it goes out of scope.

AJG85
  • 15,849
  • 13
  • 42
  • 50