Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Defined Symbols C++ error

I thought ifndef something #define something body #endif solved this error, so I'm not sure why this is happening.

//Library.h
#ifndef __LIBRARY__
#define __LIBRARY__

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdarg>
#include <vector>
#include <ctime>
#include <cmath>
#include <cstdlib>

//file includes
#include "Globals.h"

using namespace std;

#endif //__LIBRARY__

--

//globals.h
//global variables
#ifndef __GLOBAL__
#define __GLOBAL__

#include <vector>
#include <iostream>
#include <string>

//prototypes
bool Poglathon(std::vector<std::string>& text);
void NPCTalk(std::string const& speaker,std::vector<std::string> const& text);
void wait(double seconds);

//player stats
std::string name;
double str;     //strength
double wis;     //wisdom
double ref;     //reflex
double hp;      //health points
double i;       //initiative
double inte;    //intelligence
double c;       //courage
int gold;       //gold
int xp;         //experience
int ap;         //armour points
int wd;         //weapon damage
int lvl;        //level
int sp;         //skill points

#endif //__GLOBAL__

Then there's two other cpp files that include "Library.h".

like image 703
pighead10 Avatar asked Mar 20 '11 18:03

pighead10


2 Answers

The problem is that in your globals.h header file, you're declaring a suite of variables that by default have external linkage: namely, all the globals!

When you prototype a function in a header file, you are declaring a function, but not defining it. It's perfectly legal to have multiple declarations of the same function, which is why if several different files all #include the same header and declare the same function it's perfectly fine. On the other hand, if you have global variables in a header file, you are defining those variables. Variables can only be defined once in C++ (this is called the one-definition rule), and if multiple files define the same variable or function it will cause a linker error because the linker won't know which version to use. This is the reason, by the way, that you don't #include .cpp files, since if you did you'd multiply define all the functions exported by that header.

To fix this problem, in the header you'll want to change those variable definitions to variable declarations by using the extern keyword:

//player stats
extern std::string name;
extern double str;     //strength
extern double wis;     //wisdom
extern double ref;     //reflex
extern double hp;      //health points
extern double i;       //initiative
extern double inte;    //intelligence
extern double c;       //courage
extern int gold;       //gold
extern int xp;         //experience
extern int ap;         //armour points
extern int wd;         //weapon damage
extern int lvl;        //level
extern int sp;         //skill points

This will allow any number of files to #include this header, since none of them are actually defining the variables; they're just declaring that the variables will exist somewhere. Then, you should create a new .cpp file, probably globals.cpp, that actually defines the variables:

#include "globals.h"

std::string name;
double str;     //strength
double wis;     //wisdom
double ref;     //reflex
double hp;      //health points
double i;       //initiative
double inte;    //intelligence
double c;       //courage
int gold;       //gold
int xp;         //experience
int ap;         //armour points
int wd;         //weapon damage
int lvl;        //level
int sp;         //skill points

These are the actual definitions for the variables, and since they exist in just one place (globals.cpp) you won't get any more linker errors.

Hope this helps!

like image 152
templatetypedef Avatar answered Nov 14 '22 21:11

templatetypedef


There are many issues with your C++ code

  • Never declare global variables directly in the header that is what is triggering the multiple symbols as they will appear in each compilation unit (~cpp file using them) One solution would be to make them extern but I would urge you to use a class or structure holding these parameters instead.

Beside this:

  • Never do "using namespace xxx" inside header files on the global scope. You will force everyone using the header to pull the symbols inside the global namespace.
  • It is not following C++ semantics, looks more like C ( I would really wrap all player stats inside a class of the same name!)
like image 44
jdehaan Avatar answered Nov 14 '22 22:11

jdehaan