Renato Britto Araujo
Renato Britto Araujo

Reputation: 43

Multiple declaration vs not defined

I'm trying to import variables from a file that are used in a class in other file and ultimately import that to yet another file and compile.

Let me show what the reproduction of the problem looks like:

The objective is to acess the array from both the classFile.cpp and mainfile.cpp, but I'm not managing to do this.

If I don't include arrayFile.cpp in mainfile.cpp:

/tmp/cce4ZHbp.o:(.data+0x0): multiple definition of `arr'
/tmp/ccmsYdmt.o:(.data+0x0): first defined here

If I do:

In file included from mainfile.cpp:5:0:
classFolder/arrayFile.hpp:1:9: error: redefinition of ‘int arr []’
 int arr[] = {
         ^
In file included from classFolder/classFile.hpp:3:0,
                 from mainfile.cpp:4:
classFolder/arrayFile.hpp:1:5: note: ‘int arr [6]’ previously defined here
 int arr[] = {
     ^

I've was able to get the compiler to tell me arr[] was undefined too, but am unable to reproduce this error.

What am I doing wrong?

The real issue I'm facing requires me to import an array and a struct to a class, and this class is imported to yet another bigger class, this last class is finally used by main. This is my best at reproducing it. I don't know how to fix this.

Upvotes: 0

Views: 118

Answers (2)

StoneThrow
StoneThrow

Reputation: 6255

Broadly, it is not a good idea to define variables in a header file - assuming said header file will be included by multiple source files.

When you compile your project, the preprocessor handles "#include" statements by literally placing the content of the included header file in the file including it. E.g.:

// foo.h
#ifndef FOO_H
#define FOO_H
typedef int myInt;
#endif

.

// main.cpp
#include "foo.h"
int main( int argc, char* argv[] )
{
  return 0;
}

.

// preprocessor output

typedef int myInt;

int main( int argc, char* argv[] )
{
  return 0;
}

This is a simplification - but good enough for illustrative purpose. So what's happening in your example? arrayFile.hpp is included by classFile.hpp which is included by classFile.cpp and mainfile.cpp. It may be helpful to consider the include-tree:

           arrayFile.hpp
                |
           classFile.hpp
             /       \
   classFile.cpp    mainfile.cpp

Think about what I said RE: replacing includes with the included file content and see if you don't agree when I say that classFile.cpp and mainfile.cpp both end up with a definition of your arr array.

What happens next when you're compiling your project? The compiler compiles your source code - specifically, the preprocessor output - to object files. E.g. the preprocessed classFile.cpp becomes classFile.o and the preprocessed mainfile.cpp becomes mainfile.o.

Finally, object files (or the libraries they are archived into) are linked to form your executable.

When the linker tries to link classFile.o and mainfile.o it will discover that both have arr defined in them. Thus you get your multiple definition linker error - not a compiler error.

So: if a header file is included - directly or indirectly - by multiple source files, you'll run into linker errors if the header file defines variables. This is why, it is standard practice to declare variables in header files and define them in one source file.

Hope that helps.

Upvotes: 2

Meliodas
Meliodas

Reputation: 337

You should not include arrayFile.hpp inside your classFile.hpp. Include it only in classFile.cpp. Also, in mainfile.cpp (before main function) add line

extern int arr[];

This line tells the compiles that array of type int called "arr" will be defined in some other cpp file that will be linked together with mainfile.cpp.

Compile your program like this:

g++ -std=c++11 -c main.cpp classFile.cpp
g++ -std=c++11 main.o classFile.o
./a.out

First line compiles your files individually (creating main.o and classFile.o files) Second line links them together creating one executable file (a.out) Third line runs the executable file

Since adding new files makes this compilation process complicated, I suggest using a Makefile.

Upvotes: 2

Related Questions