-2

I have four C++ files that i'm trying to compile. Two are .h and two are .cpp. I created a makefile that produces two objects and compiles those with g++. There's an int defined in one of the .h files that the linker insists is defined twice. What am I doing wrong? These are the source files:

"foo.cpp"

#include "foo.h"
#include "bar.h"
int main ()
{
    X();
}

"foo.h"

#ifndef j
#define j
bool a;
#endif

"bar.cpp"

#include "bar.h"
int X()
{
    b = 0;
    return b;
}

"bar.h"

#ifndef k
#define k
int b;
int X();
#endif

"Makefile"

exec: foo.o bar.o
g++ -oexec foo.o bar.o

foo.o: foo.cpp foo.h
bar.o: bar.cpp bar.h

This is the compile error I get:

/usr/bin/ld: bar.o:(.bss+0x0): multiple definition of `b'; foo.o:(.bss+0x4): first defined here
collect2: error: ld returned 1 exit status

P.S. No, this isn't part of an assignment. I've made a simplified example for this post.

xaxxon
  • 19,189
  • 5
  • 50
  • 80
  • You should not be defining variables in your headers. When you include the header it causes the variable to be defined in multiple translation units. – drescherjm Aug 09 '18 at 22:33
  • Like the error says, you have multiple definitions of `b`, one in `bar.h` and one in `bar.cpp`. You should tell the compiler that the `b` mentioned in `bar.h` is defined elsewhere by making it `extern int b;` – alter_igel Aug 09 '18 at 22:35
  • 1
    To add to what @drescherjm said, if you need to declare a variable in a header (so it can be used in multiple .cpp files), make it "extern". That's very similar to making a data member of a class (non-inline) static. – xaxxon Aug 09 '18 at 22:35
  • 1
    every translation unit (probably cpp file) that includes bar.h gets its own `int b;`, and the poor linker can't handle that. The include guard, `#ifndef k` will prevent multiple inclusions of a header in that translation unit, but cannot help with multiple translation units, and that's what you have run up against here. – user4581301 Aug 09 '18 at 22:35
  • @alterigel on top of that, though, it's not just that there's one in a .h and one in a .cpp - having it in a .h at all will likely lead to this problem in a normal code base, as the header will likely be included from multiple .cpp files (even with an include guard which only protects against multiple includes from the same compilation unit (.cpp file)) – xaxxon Aug 09 '18 at 22:37
  • Thanks all, I had a feeling I was making a simple error. – Daniel Smith Aug 10 '18 at 01:38

1 Answers1

1

You defined the variables

bool a;
int b;

in header files, which turn where included in more than one source code, each of which created a definition in the resulting object file.

You should avoid to declare variables (other than non-static class members) in header files. If you really really need to communicate the existence of such a variable in a header file, declare it as extern:

// foo.h
extern int b;      // declares the existence of a variable named b

// foo.cpp
#include foo.h
int b;             // keeps the promise made in foo.h

// bar.h
#include foo.h
b = 2;             // modifies the variable b in foo.cpp
Walter
  • 44,150
  • 20
  • 113
  • 196